1use std::path::PathBuf;
2
3use crate::{
4 error::Error,
5 schema::{Meta, PrimSchema},
6 section::TomlContent,
7 value::{ArrayValue, PrimValue},
8 Schema, TomlValue, Value,
9};
10use serde::Serialize;
11
12pub trait TomlInput: Serialize + Sized {
13 fn schema() -> Result<Schema, Error>;
14 fn into_value(self) -> Result<Value, Error>;
15 fn schema_to_string() -> Result<String, Error> {
16 let schema = Self::schema()?;
17 let sections = schema.flatten();
18 let mut content = TomlContent { sections };
19 content.config_block_comment(false);
20 content.render()
21 }
22 fn into_string(self) -> Result<String, Error> {
23 let schema = Self::schema()?;
24 let sections = schema.flatten();
25 let mut content = TomlContent { sections };
26 let value = self.into_value()?;
27 content.merge_value(value);
28 content.render()
30 }
31}
32
33macro_rules! impl_type_info_primary {
34 ($t:ty, $name:expr) => {
35 impl TomlInput for $t {
36 fn schema() -> Result<Schema, Error> {
37 let default = <$t as Default>::default();
38 let raw = TomlValue::try_from(default)?;
39 let mut meta = Meta::default();
40 meta.inner_type = $name.to_string();
41 meta.inner_default = PrimValue::new(raw);
42 let data = PrimSchema {
43 meta,
44 ..Default::default()
45 };
46 Ok(Schema::Prim(data))
47 }
48 fn into_value(self) -> Result<Value, Error> {
49 let raw = TomlValue::try_from(self)?;
50 Ok(Value::new_prim(raw))
51 }
52 }
53 };
54}
55
56impl_type_info_primary!(bool, "bool");
57impl_type_info_primary!(String, "string");
58impl_type_info_primary!(i8, "i8");
59impl_type_info_primary!(i16, "i16");
60impl_type_info_primary!(i32, "i32");
61impl_type_info_primary!(i64, "i64");
62impl_type_info_primary!(isize, "isize");
63impl_type_info_primary!(u8, "u8");
64impl_type_info_primary!(u16, "u16");
65impl_type_info_primary!(u32, "u32");
66impl_type_info_primary!(u64, "u64");
67impl_type_info_primary!(usize, "usize");
68impl_type_info_primary!(f32, "f32");
69impl_type_info_primary!(f64, "f64");
70impl_type_info_primary!(PathBuf, "path");
71
72impl<T: TomlInput> TomlInput for Option<T> {
73 fn schema() -> Result<Schema, Error> {
74 let mut schema = T::schema()?;
75 schema.set_wrap_type("Option".to_string());
76 Ok(schema)
77 }
78 fn into_value(self) -> Result<Value, Error> {
79 if let Some(item) = self {
80 item.into_value()
81 } else {
82 Ok(Value::Prim(PrimValue::default()))
83 }
84 }
85}
86
87impl<T: TomlInput> TomlInput for Vec<T> {
88 fn schema() -> Result<Schema, Error> {
89 let mut schema = T::schema()?;
90 schema.set_wrap_type("Vec".to_string());
91 schema.meta_mut().is_array = true;
92 Ok(schema)
93 }
94 fn into_value(self) -> Result<Value, Error> {
95 let mut values = Vec::new();
96 let mut as_prim = false;
97 for item in self {
98 let value = item.into_value()?;
99 if as_prim || value.is_prim() || value.is_array() {
100 as_prim = true;
101 let prim = value.into_prim();
102 values.push(Value::Prim(prim));
103 } else {
104 values.push(value)
105 }
106 }
107 let array = ArrayValue { values };
108 if as_prim {
109 Ok(Value::Prim(array.into_prim()))
110 } else {
111 Ok(Value::Array(array))
112 }
113 }
114}