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