1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

add decoding of arrays and nested structs

This commit is contained in:
Turiiya 2023-04-20 23:42:12 +02:00 committed by Turiiya
parent 6269eacb6f
commit 288257f9a4
2 changed files with 157 additions and 43 deletions

View File

@ -1,18 +1,25 @@
import toml
enum Rank {
low
medium
high
enum JobTitle {
worker
executive
manager
}
struct Planet {
name string
population u64
size f64
avg_temp int
has_water bool
rank Rank
struct Pet {
name string
nicknames []string
age u64
income int
height f32
has_furr bool
title JobTitle
address Address
}
struct Address {
street string
city string
}
struct Employee {
@ -21,20 +28,39 @@ mut:
age int
salary f32
is_human bool
rank Rank
title JobTitle
}
struct Arrs {
strs []string
bools []bool
ints []int
i64s []i64
u64s []u64
f32s []f32
f64s []f64
dts []toml.DateTime
dates []toml.Date
times []toml.Time
}
fn test_encode_and_decode() {
p := Planet{'Mars', 0, 144.8, -81, true, .high}
s := 'name = "Mars"
population = 0
size = 144.8
avg_temp = -81
has_water = true
rank = 2'
p := Pet{'Mr. Scratchy McEvilPaws', ['Freddy', 'Fred', 'Charles'], 8, -1, 0.8, true, .manager, Address{'1428 Elm Street', 'Springwood'}}
s := 'name = "Mr. Scratchy McEvilPaws"
nicknames = [
"Freddy",
"Fred",
"Charles"
]
age = 8
income = -1
height = 0.8
has_furr = true
title = 2
address = { street = "1428 Elm Street", city = "Springwood" }'
assert toml.encode[Planet](p) == s
assert toml.decode[Planet](s)! == p
assert toml.encode[Pet](p) == s
assert toml.decode[Pet](s)! == p
}
pub fn (e Employee) to_toml() string {
@ -43,7 +69,7 @@ pub fn (e Employee) to_toml() string {
mp['age'] = toml.Any(e.age)
mp['salary'] = toml.Any(f32(e.salary) + 5000.0)
mp['is_human'] = toml.Any(e.is_human)
mp['rank'] = toml.Any(int(e.rank) + 1)
mp['title'] = toml.Any(int(e.title) + 1)
return mp.to_toml()
}
@ -53,18 +79,18 @@ pub fn (mut e Employee) from_toml(any toml.Any) {
e.age = mp['age'] or { toml.Any(0) }.int()
e.salary = mp['salary'] or { toml.Any(0) }.f32() - 15000.0
e.is_human = mp['is_human'] or { toml.Any(false) }.bool()
e.rank = unsafe { Rank(mp['rank'] or { toml.Any(0) }.int() - 2) }
e.title = unsafe { JobTitle(mp['title'] or { toml.Any(0) }.int() - 2) }
}
fn test_custom_encode_and_decode() {
x := Employee{'Peter', 28, 95000.5, true, .medium}
x := Employee{'Peter', 28, 95000.5, true, .executive}
s := toml.encode[Employee](x)
eprintln('Employee x: ${s}')
assert s == r'name = "Peter"
age = 28
salary = 100000.5
is_human = true
rank = 2'
title = 2'
y := toml.decode[Employee](s) or {
println(err)
@ -76,5 +102,62 @@ rank = 2'
assert y.age == 28
assert y.salary == 85000.5
assert y.is_human == true
assert y.rank == .low
assert y.title == .worker
}
fn test_array_encode_decode() {
a := Arrs{
strs: ['foo', 'bar']
bools: [true, false]
ints: [-1, 2]
i64s: [i64(-2)]
u64s: [u64(123)]
f32s: [f32(1.0), f32(2.5)]
f64s: [100000.5, -123.0]
dts: [toml.DateTime{'1979-05-27T07:32:00Z'}, toml.DateTime{'1979-05-27T07:32:00Z'}]
dates: [toml.Date{'1979-05-27'}, toml.Date{'2022-12-31'}]
times: [toml.Time{'07:32:59'}, toml.Time{'17:32:04'}]
}
s := 'strs = [
"foo",
"bar"
]
bools = [
true,
false
]
ints = [
-1,
2
]
i64s = [
-2
]
u64s = [
123
]
f32s = [
1.0,
2.5
]
f64s = [
100000.5,
-123.0
]
dts = [
1979-05-27T07:32:00Z,
1979-05-27T07:32:00Z
]
dates = [
1979-05-27,
2022-12-31
]
times = [
07:32:59,
17:32:04
]'
assert toml.encode[Arrs](a) == s
assert toml.decode[Arrs](s)! == a
}

View File

@ -7,7 +7,6 @@ import toml.ast
import toml.input
import toml.scanner
import toml.parser
import time
// Null is used in sumtype checks as a "default" value when nothing else is possible.
pub struct Null {
@ -24,37 +23,63 @@ pub fn decode[T](toml_txt string) !T {
return typ
}
}
typ = decode_struct[T](doc.to_any())
decode_struct[T](doc.to_any(), mut typ)
return typ
}
fn decode_struct[T](doc Any) T {
mut typ := T{}
fn decode_struct[T](doc Any, mut typ T) {
$for field in T.fields {
value := doc.value(field.name)
$if field.is_enum {
typ.$(field.name) = doc.value(field.name).int()
typ.$(field.name) = value.int()
} $else $if field.typ is string {
typ.$(field.name) = doc.value(field.name).string()
typ.$(field.name) = value.string()
} $else $if field.typ is bool {
typ.$(field.name) = doc.value(field.name).bool()
typ.$(field.name) = value.bool()
} $else $if field.typ is int {
typ.$(field.name) = doc.value(field.name).int()
typ.$(field.name) = value.int()
} $else $if field.typ is i64 {
typ.$(field.name) = doc.value(field.name).i64()
typ.$(field.name) = value.i64()
} $else $if field.typ is u64 {
typ.$(field.name) = doc.value(field.name).u64()
typ.$(field.name) = value.u64()
} $else $if field.typ is f32 {
typ.$(field.name) = doc.value(field.name).f32()
typ.$(field.name) = value.f32()
} $else $if field.typ is f64 {
typ.$(field.name) = doc.value(field.name).f64()
typ.$(field.name) = value.f64()
} $else $if field.is_array {
arr := value.array()
match typeof(typ.$(field.name)).name {
'[]string' { typ.$(field.name) = arr.as_strings() }
'[]int' { typ.$(field.name) = arr.map(it.int()) }
'[]i64' { typ.$(field.name) = arr.map(it.i64()) }
'[]u64' { typ.$(field.name) = arr.map(it.u64()) }
'[]f32' { typ.$(field.name) = arr.map(it.f32()) }
'[]f64' { typ.$(field.name) = arr.map(it.f64()) }
'[]bool' { typ.$(field.name) = arr.map(it.bool()) }
'[]toml.DateTime' { typ.$(field.name) = arr.map(it.datetime()) }
'[]toml.Date' { typ.$(field.name) = arr.map(it.date()) }
'[]toml.Time' { typ.$(field.name) = arr.map(it.time()) }
else {}
}
} $else $if field.is_struct {
// typ.$(field.name) = decode_struct(doc.value(field.name))
} $else $if field.typ is time.Time {
// TODO: extend
typ.$(field.name) = doc.value(field.name).datetime()
match typeof(typ.$(field.name)).name {
'toml.DateTime' {
// typ.$(field.name) = DateTime{value.string()}
}
'toml.Date' {
// typ.$(field.name) = Date{value.string()}
}
'toml.Time' {
// typ.$(field.name) = Time{value.string()}
}
else {
mut s := typ.$(field.name)
decode_struct(value, mut s)
typ.$(field.name) = s
}
}
}
}
return typ
}
// encode encodes the type `T` into a TOML string.
@ -77,6 +102,12 @@ fn encode_struct[T](typ T) map[string]Any {
mp[field.name] = Any(int(value))
} $else $if field.is_struct {
mp[field.name] = encode_struct(value)
} $else $if field.is_array {
mut arr := []Any{}
for v in value {
arr << Any(v)
}
mp[field.name] = arr
} $else {
mp[field.name] = Any(value)
}