Skip to content

Commit 1d6cc57

Browse files
authored
toml: add reflection method (#12664)
1 parent 0da7e2f commit 1d6cc57

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

vlib/toml/any.v

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,36 @@ fn (a Any) value_(value Any, key []string) Any {
226226
}
227227
}
228228
}
229+
230+
pub fn (a Any) reflect<T>() T {
231+
mut reflected := T{}
232+
$for field in T.fields {
233+
$if field.typ is string {
234+
reflected.$(field.name) = a.value(field.name).default_to('').string()
235+
} $else $if field.typ is bool {
236+
reflected.$(field.name) = a.value(field.name).default_to(false).bool()
237+
} $else $if field.typ is int {
238+
reflected.$(field.name) = a.value(field.name).default_to(0).int()
239+
} $else $if field.typ is f32 {
240+
reflected.$(field.name) = a.value(field.name).default_to(0.0).f32()
241+
} $else $if field.typ is f64 {
242+
reflected.$(field.name) = a.value(field.name).default_to(0.0).f64()
243+
} $else $if field.typ is i64 {
244+
reflected.$(field.name) = a.value(field.name).default_to(0).i64()
245+
} $else $if field.typ is u64 {
246+
reflected.$(field.name) = a.value(field.name).default_to(0).u64()
247+
} $else $if field.typ is Any {
248+
reflected.$(field.name) = a.value(field.name)
249+
} $else $if field.typ is DateTime {
250+
dt := DateTime{'0000-00-00T00:00:00.000'}
251+
reflected.$(field.name) = a.value(field.name).default_to(dt).datetime()
252+
} $else $if field.typ is Date {
253+
da := Date{'0000-00-00'}
254+
reflected.$(field.name) = a.value(field.name).default_to(da).date()
255+
} $else $if field.typ is Time {
256+
t := Time{'00:00:00.000'}
257+
reflected.$(field.name) = a.value(field.name).default_to(t).time()
258+
}
259+
}
260+
return reflected
261+
}

vlib/toml/tests/reflect_test.v

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import toml
2+
3+
const toml_text = '# This TOML can reflect to a struct
4+
name = "Tom"
5+
age = 45
6+
height = 1.97
7+
8+
birthday = 1980-04-23
9+
10+
[bio]
11+
text = "Tom has done many great things"
12+
years_of_service = 5
13+
14+
[config]
15+
data = [ 1, 2, 3 ]
16+
levels = { "info" = 1, "warn" = 2, "critical" = 3 }
17+
'
18+
19+
struct Bio {
20+
text string
21+
years_of_service int
22+
}
23+
24+
struct User {
25+
name string
26+
age int
27+
height f64
28+
birthday toml.Date
29+
30+
config toml.Any
31+
mut:
32+
bio Bio
33+
}
34+
35+
fn test_reflect() {
36+
toml_doc := toml.parse(toml_text) or { panic(err) }
37+
38+
mut user := toml_doc.reflect<User>()
39+
user.bio = toml_doc.value('bio').reflect<Bio>()
40+
41+
assert user.name == 'Tom'
42+
assert user.age == 45
43+
assert user.height == 1.97
44+
assert user.birthday.str() == '1980-04-23'
45+
assert user.bio.text == 'Tom has done many great things'
46+
assert user.bio.years_of_service == 5
47+
48+
assert user.config.value('data[0]').int() == 1
49+
assert user.config.value('levels.warn').int() == 2
50+
}

vlib/toml/toml.v

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ pub fn (d Doc) to_any() Any {
173173
return ast_to_any(d.ast.table)
174174
}
175175

176+
pub fn (d Doc) reflect<T>() T {
177+
return d.to_any().reflect<T>()
178+
}
179+
176180
// value queries a value from the TOML document.
177181
// `key` supports a small query syntax scheme:
178182
// Maps can be queried in "dotted" form e.g. `a.b.c`.

0 commit comments

Comments
 (0)