toml: add `encode<T>` and `decode<T>` (#13244)
parent
7ae96f0e38
commit
2b4f7e7685
|
@ -33,6 +33,41 @@ pub fn (a Any) string() string {
|
|||
}
|
||||
}
|
||||
|
||||
// to_toml returns `Any` as a TOML encoded value.
|
||||
pub fn (a Any) to_toml() string {
|
||||
match a {
|
||||
map[string]Any {
|
||||
// TODO more format control?
|
||||
return a.to_inline_toml()
|
||||
}
|
||||
[]Any {
|
||||
return a.to_toml()
|
||||
}
|
||||
bool, f32, f64, i64, int, u64 {
|
||||
return a.str().clone()
|
||||
}
|
||||
// NOTE if `.clone()` is not used here:
|
||||
// string { return a as string }
|
||||
// ... certain call-patterns to this function will cause a memory corruption.
|
||||
// See `tests/toml_memory_corruption_test.v` for a matching regression test.
|
||||
string {
|
||||
return '"' + (a as string).clone() + '"'
|
||||
}
|
||||
DateTime {
|
||||
return a.str().clone()
|
||||
}
|
||||
Date {
|
||||
return a.str().clone()
|
||||
}
|
||||
Time {
|
||||
return a.str().clone()
|
||||
}
|
||||
else {
|
||||
return a.str().clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// int returns `Any` as an 32-bit integer.
|
||||
pub fn (a Any) int() int {
|
||||
match a {
|
||||
|
@ -181,6 +216,35 @@ pub fn (m map[string]Any) as_strings() map[string]string {
|
|||
return result
|
||||
}
|
||||
|
||||
// to_toml returns the contents of the map
|
||||
// as a TOML encoded `string`.
|
||||
pub fn (m map[string]Any) to_toml() string {
|
||||
mut toml_text := ''
|
||||
for k, v in m {
|
||||
mut key := k
|
||||
if key.contains(' ') {
|
||||
key = '"$key"'
|
||||
}
|
||||
toml_text += '$key = ' + v.to_toml() + '\n'
|
||||
}
|
||||
toml_text = toml_text.trim_right('\n')
|
||||
return toml_text
|
||||
}
|
||||
|
||||
// to_inline_toml returns the contents of the map
|
||||
// as an inline table encoded TOML `string`.
|
||||
pub fn (m map[string]Any) to_inline_toml() string {
|
||||
mut toml_text := '{'
|
||||
for k, v in m {
|
||||
mut key := k
|
||||
if key.contains(' ') {
|
||||
key = '"$key"'
|
||||
}
|
||||
toml_text += ' $key = ' + v.to_toml() + ','
|
||||
}
|
||||
return toml_text + ' }'
|
||||
}
|
||||
|
||||
// value queries a value from the array.
|
||||
// `key` supports a small query syntax scheme:
|
||||
// The array can be queried with `[0].b[1].[2]`.
|
||||
|
@ -200,6 +264,17 @@ pub fn (a []Any) as_strings() []string {
|
|||
return sa
|
||||
}
|
||||
|
||||
// to_toml returns the contents of the array
|
||||
// as a TOML encoded `string`.
|
||||
pub fn (a []Any) to_toml() string {
|
||||
mut toml_text := '[\n'
|
||||
for any in a {
|
||||
toml_text += ' ' + any.to_toml() + ',\n'
|
||||
}
|
||||
toml_text = toml_text.trim_right(',\n')
|
||||
return toml_text + '\n]'
|
||||
}
|
||||
|
||||
// value queries a value from the `Any` type.
|
||||
// `key` supports a small query syntax scheme:
|
||||
// Maps can be queried in "dotted" form e.g. `a.b.c`.
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import toml
|
||||
|
||||
enum JobTitle {
|
||||
manager
|
||||
executive
|
||||
worker
|
||||
}
|
||||
|
||||
struct Employee {
|
||||
pub mut:
|
||||
name string
|
||||
age int
|
||||
salary f32
|
||||
is_human bool
|
||||
title JobTitle
|
||||
}
|
||||
|
||||
fn (e Employee) to_toml() string {
|
||||
mut mp := map[string]toml.Any{}
|
||||
mp['name'] = toml.Any(e.name)
|
||||
mp['age'] = toml.Any(e.age)
|
||||
mp['salary'] = toml.Any(e.salary)
|
||||
mp['is_human'] = toml.Any(e.is_human)
|
||||
mp['title'] = toml.Any(int(e.title))
|
||||
return mp.to_toml()
|
||||
}
|
||||
|
||||
fn (mut e Employee) from_toml(any toml.Any) {
|
||||
mp := any.as_map()
|
||||
e.name = mp['name'] or { toml.Any('') }.string()
|
||||
e.age = mp['age'] or { toml.Any(0) }.int()
|
||||
e.salary = mp['salary'] or { toml.Any(0) }.f32()
|
||||
e.is_human = mp['is_human'] or { toml.Any(false) }.bool()
|
||||
e.title = JobTitle(mp['title'] or { toml.Any(0) }.int())
|
||||
}
|
||||
|
||||
fn test_encode_and_decode() {
|
||||
x := Employee{'Peter', 28, 95000.5, true, .worker}
|
||||
s := toml.encode<Employee>(x)
|
||||
eprintln('Employee x: $s')
|
||||
assert s == r'name = "Peter"
|
||||
age = 28
|
||||
salary = 95000.5
|
||||
is_human = true
|
||||
title = 2'
|
||||
|
||||
y := toml.decode<Employee>(s) or {
|
||||
println(err)
|
||||
assert false
|
||||
return
|
||||
}
|
||||
eprintln('Employee y: $y')
|
||||
assert y.name == 'Peter'
|
||||
assert y.age == 28
|
||||
assert y.salary == 95000.5
|
||||
assert y.is_human == true
|
||||
assert y.title == .worker
|
||||
}
|
|
@ -12,6 +12,20 @@ import toml.parser
|
|||
pub struct Null {
|
||||
}
|
||||
|
||||
// decode decodes a TOML `string` into the target type `T`.
|
||||
pub fn decode<T>(toml_txt string) ?T {
|
||||
doc := parse_text(toml_txt) ?
|
||||
mut typ := T{}
|
||||
typ.from_toml(doc.to_any())
|
||||
return typ
|
||||
}
|
||||
|
||||
// encode encodes the type `T` into a JSON string.
|
||||
// Currently encode expects the method `.to_toml()` exists on `T`.
|
||||
pub fn encode<T>(typ T) string {
|
||||
return typ.to_toml()
|
||||
}
|
||||
|
||||
// DateTime is the representation of an RFC 3339 datetime string.
|
||||
pub struct DateTime {
|
||||
datetime string
|
||||
|
|
Loading…
Reference in New Issue