mirror of
https://github.com/vlang/v.git
synced 2025-08-03 17:57:59 -04:00
toml: add reflect/decode struct default value support (#22412)
This commit is contained in:
parent
209c30f3a6
commit
3c0358cce7
@ -330,106 +330,110 @@ pub fn (a Any) reflect[T]() T {
|
|||||||
mut reflected := T{}
|
mut reflected := T{}
|
||||||
$for field in T.fields {
|
$for field in T.fields {
|
||||||
mut toml_field_name := field.name
|
mut toml_field_name := field.name
|
||||||
|
mut skip := false
|
||||||
// Remapping of field names, for example:
|
// Remapping of field names, for example:
|
||||||
// TOML: 'assert = "ok"'
|
// TOML: 'assert = "ok"'
|
||||||
// V: User { asrt string @[toml: 'assert'] }
|
// V: User { asrt string @[toml: 'assert'] }
|
||||||
// User.asrt == 'ok'
|
// User.asrt == 'ok'
|
||||||
for attr in field.attrs {
|
for attr in field.attrs {
|
||||||
|
if attr == 'skip' {
|
||||||
|
skip = true
|
||||||
|
break
|
||||||
|
}
|
||||||
if attr.starts_with('toml:') {
|
if attr.starts_with('toml:') {
|
||||||
toml_field_name = attr.all_after(':').trim_space()
|
toml_field_name = attr.all_after(':').trim_space()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
value := a.value(toml_field_name)
|
||||||
|
// only set the field's value when value != null and !skip, else field got it's default value
|
||||||
|
if !skip && value != null {
|
||||||
$if field.typ is string {
|
$if field.typ is string {
|
||||||
reflected.$(field.name) = a.value(toml_field_name).default_to('').string()
|
reflected.$(field.name) = value.string()
|
||||||
} $else $if field.typ is bool {
|
} $else $if field.typ is bool {
|
||||||
reflected.$(field.name) = a.value(toml_field_name).default_to(false).bool()
|
reflected.$(field.name) = value.bool()
|
||||||
} $else $if field.typ is int {
|
} $else $if field.typ is int {
|
||||||
reflected.$(field.name) = a.value(toml_field_name).default_to(0).int()
|
reflected.$(field.name) = value.int()
|
||||||
} $else $if field.typ is f32 {
|
} $else $if field.typ is f32 {
|
||||||
reflected.$(field.name) = a.value(toml_field_name).default_to(0.0).f32()
|
reflected.$(field.name) = value.f32()
|
||||||
} $else $if field.typ is f64 {
|
} $else $if field.typ is f64 {
|
||||||
reflected.$(field.name) = a.value(toml_field_name).default_to(0.0).f64()
|
reflected.$(field.name) = value.f64()
|
||||||
} $else $if field.typ is i64 {
|
} $else $if field.typ is i64 {
|
||||||
reflected.$(field.name) = a.value(toml_field_name).default_to(0).i64()
|
reflected.$(field.name) = value.i64()
|
||||||
} $else $if field.typ is u64 {
|
} $else $if field.typ is u64 {
|
||||||
reflected.$(field.name) = a.value(toml_field_name).default_to(0).u64()
|
reflected.$(field.name) = value.u64()
|
||||||
} $else $if field.typ is Any {
|
} $else $if field.typ is Any {
|
||||||
reflected.$(field.name) = a.value(toml_field_name)
|
reflected.$(field.name) = value
|
||||||
} $else $if field.typ is DateTime {
|
} $else $if field.typ is DateTime {
|
||||||
dt := DateTime{'0000-00-00T00:00:00.000'}
|
reflected.$(field.name) = value.datetime()
|
||||||
reflected.$(field.name) = a.value(toml_field_name).default_to(dt).datetime()
|
|
||||||
} $else $if field.typ is Date {
|
} $else $if field.typ is Date {
|
||||||
da := Date{'0000-00-00'}
|
reflected.$(field.name) = value.date()
|
||||||
reflected.$(field.name) = a.value(toml_field_name).default_to(da).date()
|
|
||||||
} $else $if field.typ is Time {
|
} $else $if field.typ is Time {
|
||||||
t := Time{'00:00:00.000'}
|
reflected.$(field.name) = value.time()
|
||||||
reflected.$(field.name) = a.value(toml_field_name).default_to(t).time()
|
|
||||||
}
|
}
|
||||||
// Arrays of primitive types
|
// Arrays of primitive types
|
||||||
$else $if field.typ is []string {
|
$else $if field.typ is []string {
|
||||||
any_array := a.value(toml_field_name).array()
|
any_array := value.array()
|
||||||
reflected.$(field.name) = any_array.as_strings()
|
reflected.$(field.name) = any_array.as_strings()
|
||||||
} $else $if field.typ is []bool {
|
} $else $if field.typ is []bool {
|
||||||
any_array := a.value(toml_field_name).array()
|
any_array := value.array()
|
||||||
mut arr := []bool{cap: any_array.len}
|
mut arr := []bool{cap: any_array.len}
|
||||||
for any_value in any_array {
|
for any_value in any_array {
|
||||||
arr << any_value.bool()
|
arr << any_value.bool()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = arr
|
reflected.$(field.name) = arr
|
||||||
} $else $if field.typ is []int {
|
} $else $if field.typ is []int {
|
||||||
any_array := a.value(toml_field_name).array()
|
any_array := value.array()
|
||||||
mut arr := []int{cap: any_array.len}
|
mut arr := []int{cap: any_array.len}
|
||||||
for any_value in any_array {
|
for any_value in any_array {
|
||||||
arr << any_value.int()
|
arr << any_value.int()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = arr
|
reflected.$(field.name) = arr
|
||||||
} $else $if field.typ is []f32 {
|
} $else $if field.typ is []f32 {
|
||||||
any_array := a.value(toml_field_name).array()
|
any_array := value.array()
|
||||||
mut arr := []f32{cap: any_array.len}
|
mut arr := []f32{cap: any_array.len}
|
||||||
for any_value in any_array {
|
for any_value in any_array {
|
||||||
arr << any_value.f32()
|
arr << any_value.f32()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = arr
|
reflected.$(field.name) = arr
|
||||||
} $else $if field.typ is []f64 {
|
} $else $if field.typ is []f64 {
|
||||||
any_array := a.value(toml_field_name).array()
|
any_array := value.array()
|
||||||
mut arr := []f64{cap: any_array.len}
|
mut arr := []f64{cap: any_array.len}
|
||||||
for any_value in any_array {
|
for any_value in any_array {
|
||||||
arr << any_value.f64()
|
arr << any_value.f64()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = arr
|
reflected.$(field.name) = arr
|
||||||
} $else $if field.typ is []i64 {
|
} $else $if field.typ is []i64 {
|
||||||
any_array := a.value(toml_field_name).array()
|
any_array := value.array()
|
||||||
mut arr := []i64{cap: any_array.len}
|
mut arr := []i64{cap: any_array.len}
|
||||||
for any_value in any_array {
|
for any_value in any_array {
|
||||||
arr << any_value.i64()
|
arr << any_value.i64()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = arr
|
reflected.$(field.name) = arr
|
||||||
} $else $if field.typ is []u64 {
|
} $else $if field.typ is []u64 {
|
||||||
any_array := a.value(toml_field_name).array()
|
any_array := value.array()
|
||||||
mut arr := []u64{cap: any_array.len}
|
mut arr := []u64{cap: any_array.len}
|
||||||
for any_value in any_array {
|
for any_value in any_array {
|
||||||
arr << any_value.u64()
|
arr << any_value.u64()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = arr
|
reflected.$(field.name) = arr
|
||||||
} $else $if field.typ is []Any {
|
} $else $if field.typ is []Any {
|
||||||
reflected.$(field.name) = a.value(toml_field_name).array()
|
reflected.$(field.name) = value.array()
|
||||||
} $else $if field.typ is []DateTime {
|
} $else $if field.typ is []DateTime {
|
||||||
any_array := a.value(toml_field_name).array()
|
any_array := value.array()
|
||||||
mut arr := []DateTime{cap: any_array.len}
|
mut arr := []DateTime{cap: any_array.len}
|
||||||
for any_value in any_array {
|
for any_value in any_array {
|
||||||
arr << any_value.datetime()
|
arr << any_value.datetime()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = arr
|
reflected.$(field.name) = arr
|
||||||
} $else $if field.typ is []Date {
|
} $else $if field.typ is []Date {
|
||||||
any_array := a.value(toml_field_name).array()
|
any_array := value.array()
|
||||||
mut arr := []Date{cap: any_array.len}
|
mut arr := []Date{cap: any_array.len}
|
||||||
for any_value in any_array {
|
for any_value in any_array {
|
||||||
arr << any_value.date()
|
arr << any_value.date()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = arr
|
reflected.$(field.name) = arr
|
||||||
} $else $if field.typ is []Time {
|
} $else $if field.typ is []Time {
|
||||||
any_array := a.value(toml_field_name).array()
|
any_array := value.array()
|
||||||
mut arr := []Time{cap: any_array.len}
|
mut arr := []Time{cap: any_array.len}
|
||||||
for any_value in any_array {
|
for any_value in any_array {
|
||||||
arr << any_value.time()
|
arr << any_value.time()
|
||||||
@ -438,68 +442,68 @@ pub fn (a Any) reflect[T]() T {
|
|||||||
}
|
}
|
||||||
// String key maps of primitive types
|
// String key maps of primitive types
|
||||||
$else $if field.typ is map[string]string {
|
$else $if field.typ is map[string]string {
|
||||||
any_map := a.value(toml_field_name).as_map()
|
any_map := value.as_map()
|
||||||
reflected.$(field.name) = any_map.as_strings()
|
reflected.$(field.name) = any_map.as_strings()
|
||||||
} $else $if field.typ is map[string]bool {
|
} $else $if field.typ is map[string]bool {
|
||||||
any_map := a.value(toml_field_name).as_map()
|
any_map := value.as_map()
|
||||||
mut type_map := map[string]bool{}
|
mut type_map := map[string]bool{}
|
||||||
for k, any_value in any_map {
|
for k, any_value in any_map {
|
||||||
type_map[k] = any_value.bool()
|
type_map[k] = any_value.bool()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = type_map.clone()
|
reflected.$(field.name) = type_map.clone()
|
||||||
} $else $if field.typ is map[string]int {
|
} $else $if field.typ is map[string]int {
|
||||||
any_map := a.value(toml_field_name).as_map()
|
any_map := value.as_map()
|
||||||
mut type_map := map[string]int{}
|
mut type_map := map[string]int{}
|
||||||
for k, any_value in any_map {
|
for k, any_value in any_map {
|
||||||
type_map[k] = any_value.int()
|
type_map[k] = any_value.int()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = type_map.clone()
|
reflected.$(field.name) = type_map.clone()
|
||||||
} $else $if field.typ is map[string]f32 {
|
} $else $if field.typ is map[string]f32 {
|
||||||
any_map := a.value(toml_field_name).as_map()
|
any_map := value.as_map()
|
||||||
mut type_map := map[string]f32{}
|
mut type_map := map[string]f32{}
|
||||||
for k, any_value in any_map {
|
for k, any_value in any_map {
|
||||||
type_map[k] = any_value.f32()
|
type_map[k] = any_value.f32()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = type_map.clone()
|
reflected.$(field.name) = type_map.clone()
|
||||||
} $else $if field.typ is map[string]f64 {
|
} $else $if field.typ is map[string]f64 {
|
||||||
any_map := a.value(toml_field_name).as_map()
|
any_map := value.as_map()
|
||||||
mut type_map := map[string]f64{}
|
mut type_map := map[string]f64{}
|
||||||
for k, any_value in any_map {
|
for k, any_value in any_map {
|
||||||
type_map[k] = any_value.f64()
|
type_map[k] = any_value.f64()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = type_map.clone()
|
reflected.$(field.name) = type_map.clone()
|
||||||
} $else $if field.typ is map[string]i64 {
|
} $else $if field.typ is map[string]i64 {
|
||||||
any_map := a.value(toml_field_name).as_map()
|
any_map := value.as_map()
|
||||||
mut type_map := map[string]i64{}
|
mut type_map := map[string]i64{}
|
||||||
for k, any_value in any_map {
|
for k, any_value in any_map {
|
||||||
type_map[k] = any_value.i64()
|
type_map[k] = any_value.i64()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = type_map.clone()
|
reflected.$(field.name) = type_map.clone()
|
||||||
} $else $if field.typ is map[string]u64 {
|
} $else $if field.typ is map[string]u64 {
|
||||||
any_map := a.value(toml_field_name).as_map()
|
any_map := value.as_map()
|
||||||
mut type_map := map[string]u64{}
|
mut type_map := map[string]u64{}
|
||||||
for k, any_value in any_map {
|
for k, any_value in any_map {
|
||||||
type_map[k] = any_value.u64()
|
type_map[k] = any_value.u64()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = type_map.clone()
|
reflected.$(field.name) = type_map.clone()
|
||||||
} $else $if field.typ is map[string]Any {
|
} $else $if field.typ is map[string]Any {
|
||||||
reflected.$(field.name) = a.value(toml_field_name).as_map()
|
reflected.$(field.name) = value.as_map()
|
||||||
} $else $if field.typ is map[string]DateTime {
|
} $else $if field.typ is map[string]DateTime {
|
||||||
any_map := a.value(toml_field_name).as_map()
|
any_map := value.as_map()
|
||||||
mut type_map := map[string]DateTime{}
|
mut type_map := map[string]DateTime{}
|
||||||
for k, any_value in any_map {
|
for k, any_value in any_map {
|
||||||
type_map[k] = any_value.datetime()
|
type_map[k] = any_value.datetime()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = type_map.clone()
|
reflected.$(field.name) = type_map.clone()
|
||||||
} $else $if field.typ is map[string]Date {
|
} $else $if field.typ is map[string]Date {
|
||||||
any_map := a.value(toml_field_name).as_map()
|
any_map := value.as_map()
|
||||||
mut type_map := map[string]Date{}
|
mut type_map := map[string]Date{}
|
||||||
for k, any_value in any_map {
|
for k, any_value in any_map {
|
||||||
type_map[k] = any_value.date()
|
type_map[k] = any_value.date()
|
||||||
}
|
}
|
||||||
reflected.$(field.name) = type_map.clone()
|
reflected.$(field.name) = type_map.clone()
|
||||||
} $else $if field.typ is map[string]Time {
|
} $else $if field.typ is map[string]Time {
|
||||||
any_map := a.value(toml_field_name).as_map()
|
any_map := value.as_map()
|
||||||
mut type_map := map[string]Time{}
|
mut type_map := map[string]Time{}
|
||||||
for k, any_value in any_map {
|
for k, any_value in any_map {
|
||||||
type_map[k] = any_value.time()
|
type_map[k] = any_value.time()
|
||||||
@ -507,5 +511,6 @@ pub fn (a Any) reflect[T]() T {
|
|||||||
reflected.$(field.name) = type_map.clone()
|
reflected.$(field.name) = type_map.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return reflected
|
return reflected
|
||||||
}
|
}
|
||||||
|
85
vlib/toml/tests/default_value_test.v
Normal file
85
vlib/toml/tests/default_value_test.v
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import toml
|
||||||
|
|
||||||
|
const toml_text = '# This TOML can reflect/decode to a struct
|
||||||
|
val_string = "test"
|
||||||
|
val_bool = false
|
||||||
|
val_int = 456
|
||||||
|
val_i64 = 4567
|
||||||
|
val_u64 = 45678
|
||||||
|
val_f32 = 200.2
|
||||||
|
val_f64 = 2000.2
|
||||||
|
val_datetime = 2024-10-05 09:10:20.000
|
||||||
|
val_date = 2099-09-09
|
||||||
|
val_time = 22:22:22.222
|
||||||
|
'
|
||||||
|
|
||||||
|
const toml_all_default_text = '# This TOML can reflect/decode to a struct all with default values'
|
||||||
|
|
||||||
|
struct Test {
|
||||||
|
val_string string = 'abcd'
|
||||||
|
val_bool bool = true
|
||||||
|
val_int int = 123
|
||||||
|
val_i64 i64 = 1234
|
||||||
|
val_u64 u64 = 12345
|
||||||
|
val_f32 f32 = 100.1
|
||||||
|
val_f64 f64 = 1000.1
|
||||||
|
val_datetime toml.DateTime = toml.DateTime{'1980-07-11 21:23:42.123'}
|
||||||
|
val_date toml.Date = toml.Date{'1977-07-07'}
|
||||||
|
val_time toml.Time = toml.Time{'11:11:11.111'}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_reflect_default_values() {
|
||||||
|
toml_has_values := toml.parse_text(toml_text) or { panic(err) }
|
||||||
|
test_has_values := toml_has_values.reflect[Test]()
|
||||||
|
|
||||||
|
assert test_has_values.val_string == 'test'
|
||||||
|
assert test_has_values.val_bool == false
|
||||||
|
assert test_has_values.val_int == 456
|
||||||
|
assert test_has_values.val_i64 == 4567
|
||||||
|
assert test_has_values.val_u64 == 45678
|
||||||
|
assert test_has_values.val_f32 == 200.2
|
||||||
|
assert test_has_values.val_f64 == 2000.2
|
||||||
|
assert test_has_values.val_datetime == toml.DateTime{'2024-10-05 09:10:20.000'}
|
||||||
|
assert test_has_values.val_date == toml.Date{'2099-09-09'}
|
||||||
|
assert test_has_values.val_time == toml.Time{'22:22:22.222'}
|
||||||
|
|
||||||
|
toml_all_default_values := toml.parse_text(toml_all_default_text) or { panic(err) }
|
||||||
|
test_all_default_values := toml_all_default_values.reflect[Test]()
|
||||||
|
|
||||||
|
assert test_all_default_values.val_string == 'abcd'
|
||||||
|
assert test_all_default_values.val_bool == true
|
||||||
|
assert test_all_default_values.val_int == 123
|
||||||
|
assert test_all_default_values.val_i64 == 1234
|
||||||
|
assert test_all_default_values.val_u64 == 12345
|
||||||
|
assert test_all_default_values.val_f32 == 100.1
|
||||||
|
assert test_all_default_values.val_f64 == 1000.1
|
||||||
|
assert test_all_default_values.val_datetime == toml.DateTime{'1980-07-11 21:23:42.123'}
|
||||||
|
assert test_all_default_values.val_date == toml.Date{'1977-07-07'}
|
||||||
|
assert test_all_default_values.val_time == toml.Time{'11:11:11.111'}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_decode_struct_default_values() {
|
||||||
|
test_has_values := toml.decode[Test](toml_text) or { panic(err) }
|
||||||
|
assert test_has_values.val_string == 'test'
|
||||||
|
assert test_has_values.val_bool == false
|
||||||
|
assert test_has_values.val_int == 456
|
||||||
|
assert test_has_values.val_i64 == 4567
|
||||||
|
assert test_has_values.val_u64 == 45678
|
||||||
|
assert test_has_values.val_f32 == 200.2
|
||||||
|
assert test_has_values.val_f64 == 2000.2
|
||||||
|
assert test_has_values.val_datetime == toml.DateTime{'2024-10-05 09:10:20.000'}
|
||||||
|
assert test_has_values.val_date == toml.Date{'2099-09-09'}
|
||||||
|
assert test_has_values.val_time == toml.Time{'22:22:22.222'}
|
||||||
|
|
||||||
|
test_all_default_values := toml.decode[Test](toml_all_default_text) or { panic(err) }
|
||||||
|
assert test_all_default_values.val_string == 'abcd'
|
||||||
|
assert test_all_default_values.val_bool == true
|
||||||
|
assert test_all_default_values.val_int == 123
|
||||||
|
assert test_all_default_values.val_i64 == 1234
|
||||||
|
assert test_all_default_values.val_u64 == 12345
|
||||||
|
assert test_all_default_values.val_f32 == 100.1
|
||||||
|
assert test_all_default_values.val_f64 == 1000.1
|
||||||
|
assert test_all_default_values.val_datetime == toml.DateTime{'1980-07-11 21:23:42.123'}
|
||||||
|
assert test_all_default_values.val_date == toml.Date{'1977-07-07'}
|
||||||
|
assert test_all_default_values.val_time == toml.Time{'11:11:11.111'}
|
||||||
|
}
|
@ -44,8 +44,9 @@ fn decode_struct[T](doc Any, mut typ T) {
|
|||||||
field_name = attr.all_after(':').trim_space()
|
field_name = attr.all_after(':').trim_space()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !skip {
|
|
||||||
value := doc.value(field_name)
|
value := doc.value(field_name)
|
||||||
|
// only set the field's value when value != null and !skip, else field got it's default value
|
||||||
|
if !skip && value != null {
|
||||||
$if field.is_enum {
|
$if field.is_enum {
|
||||||
typ.$(field.name) = value.int()
|
typ.$(field.name) = value.int()
|
||||||
} $else $if field.typ is string {
|
} $else $if field.typ is string {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user