toml_input/
toml_input.rs

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        // dbg!(&content.sections);
29        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}