From 1d6cc57d9c234129cd0ae49572e70858fb6fb080 Mon Sep 17 00:00:00 2001 From: Larpon Date: Fri, 3 Dec 2021 11:40:46 +0100 Subject: [PATCH] toml: add reflection method (#12664) --- vlib/toml/any.v | 33 ++++++++++++++++++++++ vlib/toml/tests/reflect_test.v | 50 ++++++++++++++++++++++++++++++++++ vlib/toml/toml.v | 4 +++ 3 files changed, 87 insertions(+) create mode 100644 vlib/toml/tests/reflect_test.v diff --git a/vlib/toml/any.v b/vlib/toml/any.v index b111e1cdcb..b928e94eb0 100644 --- a/vlib/toml/any.v +++ b/vlib/toml/any.v @@ -226,3 +226,36 @@ fn (a Any) value_(value Any, key []string) Any { } } } + +pub fn (a Any) reflect() T { + mut reflected := T{} + $for field in T.fields { + $if field.typ is string { + reflected.$(field.name) = a.value(field.name).default_to('').string() + } $else $if field.typ is bool { + reflected.$(field.name) = a.value(field.name).default_to(false).bool() + } $else $if field.typ is int { + reflected.$(field.name) = a.value(field.name).default_to(0).int() + } $else $if field.typ is f32 { + reflected.$(field.name) = a.value(field.name).default_to(0.0).f32() + } $else $if field.typ is f64 { + reflected.$(field.name) = a.value(field.name).default_to(0.0).f64() + } $else $if field.typ is i64 { + reflected.$(field.name) = a.value(field.name).default_to(0).i64() + } $else $if field.typ is u64 { + reflected.$(field.name) = a.value(field.name).default_to(0).u64() + } $else $if field.typ is Any { + reflected.$(field.name) = a.value(field.name) + } $else $if field.typ is DateTime { + dt := DateTime{'0000-00-00T00:00:00.000'} + reflected.$(field.name) = a.value(field.name).default_to(dt).datetime() + } $else $if field.typ is Date { + da := Date{'0000-00-00'} + reflected.$(field.name) = a.value(field.name).default_to(da).date() + } $else $if field.typ is Time { + t := Time{'00:00:00.000'} + reflected.$(field.name) = a.value(field.name).default_to(t).time() + } + } + return reflected +} diff --git a/vlib/toml/tests/reflect_test.v b/vlib/toml/tests/reflect_test.v new file mode 100644 index 0000000000..52bc1e655d --- /dev/null +++ b/vlib/toml/tests/reflect_test.v @@ -0,0 +1,50 @@ +import toml + +const toml_text = '# This TOML can reflect to a struct +name = "Tom" +age = 45 +height = 1.97 + +birthday = 1980-04-23 + +[bio] +text = "Tom has done many great things" +years_of_service = 5 + +[config] +data = [ 1, 2, 3 ] +levels = { "info" = 1, "warn" = 2, "critical" = 3 } +' + +struct Bio { + text string + years_of_service int +} + +struct User { + name string + age int + height f64 + birthday toml.Date + + config toml.Any +mut: + bio Bio +} + +fn test_reflect() { + toml_doc := toml.parse(toml_text) or { panic(err) } + + mut user := toml_doc.reflect() + user.bio = toml_doc.value('bio').reflect() + + assert user.name == 'Tom' + assert user.age == 45 + assert user.height == 1.97 + assert user.birthday.str() == '1980-04-23' + assert user.bio.text == 'Tom has done many great things' + assert user.bio.years_of_service == 5 + + assert user.config.value('data[0]').int() == 1 + assert user.config.value('levels.warn').int() == 2 +} diff --git a/vlib/toml/toml.v b/vlib/toml/toml.v index b72014e1fb..910f647864 100644 --- a/vlib/toml/toml.v +++ b/vlib/toml/toml.v @@ -173,6 +173,10 @@ pub fn (d Doc) to_any() Any { return ast_to_any(d.ast.table) } +pub fn (d Doc) reflect() T { + return d.to_any().reflect() +} + // value queries a value from the TOML document. // `key` supports a small query syntax scheme: // Maps can be queried in "dotted" form e.g. `a.b.c`.