libgir/config/
child_properties.rs

1use log::error;
2use toml::Value;
3
4use super::{error::TomlHelper, parsable::Parse};
5
6#[derive(Clone, Debug)]
7pub struct ChildProperty {
8    pub name: String,
9    pub rename_getter: Option<String>,
10    pub type_name: String,
11    pub doc_hidden: bool,
12    pub generate_doc: bool,
13}
14
15impl Parse for ChildProperty {
16    fn parse(toml: &Value, object_name: &str) -> Option<Self> {
17        let name = toml
18            .lookup("name")
19            .and_then(Value::as_str)
20            .map(ToOwned::to_owned);
21        let name = if let Some(name) = name {
22            name
23        } else {
24            error!("No child property name for `{}`", object_name);
25            return None;
26        };
27
28        toml.check_unwanted(
29            &["name", "type", "doc_hidden", "rename_getter"],
30            &format!("child property {object_name}"),
31        );
32
33        let type_name = toml
34            .lookup("type")
35            .and_then(Value::as_str)
36            .map(ToOwned::to_owned);
37        let type_name = if let Some(type_name) = type_name {
38            type_name
39        } else {
40            error!(
41                "No type for child property `{}` for `{}`",
42                name, object_name
43            );
44            return None;
45        };
46        let doc_hidden = toml
47            .lookup("doc_hidden")
48            .and_then(Value::as_bool)
49            .unwrap_or(false);
50        let rename_getter = toml
51            .lookup("rename_getter")
52            .and_then(Value::as_str)
53            .map(ToOwned::to_owned);
54        let generate_doc = toml
55            .lookup("generate_doc")
56            .and_then(Value::as_bool)
57            .unwrap_or(true);
58
59        Some(Self {
60            name,
61            rename_getter,
62            type_name,
63            doc_hidden,
64            generate_doc,
65        })
66    }
67}
68
69#[derive(Clone, Debug)]
70pub struct ChildProperties {
71    pub child_name: Option<String>,
72    pub child_type: Option<String>,
73    pub properties: Vec<ChildProperty>,
74}
75
76impl Parse for ChildProperties {
77    fn parse(toml_object: &Value, object_name: &str) -> Option<Self> {
78        let child_name = toml_object
79            .lookup("child_name")
80            .and_then(Value::as_str)
81            .map(ToOwned::to_owned);
82        let child_type = toml_object
83            .lookup("child_type")
84            .and_then(Value::as_str)
85            .map(ToOwned::to_owned);
86        let mut properties: Vec<ChildProperty> = Vec::new();
87        if let Some(configs) = toml_object.lookup("child_prop").and_then(Value::as_array) {
88            for config in configs {
89                if let Some(item) = ChildProperty::parse(config, object_name) {
90                    properties.push(item);
91                }
92            }
93        }
94
95        if !properties.is_empty() {
96            Some(Self {
97                child_name,
98                child_type,
99                properties,
100            })
101        } else {
102            if child_name.is_some() {
103                error!("`{}` has child_name but no child_prop's", object_name);
104            }
105            if child_type.is_some() {
106                error!("`{}` has child_type but no child_prop's", object_name);
107            }
108            None
109        }
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::{super::parsable::Parse, *};
116
117    fn toml(input: &str) -> ::toml::Value {
118        let value = ::toml::from_str(input);
119        assert!(value.is_ok());
120        value.unwrap()
121    }
122
123    #[test]
124    fn child_property_parse() {
125        let toml = toml(
126            r#"
127name = "prop"
128type = "prop_type"
129"#,
130        );
131        let child = ChildProperty::parse(&toml, "a").unwrap();
132        assert_eq!("prop", child.name);
133        assert_eq!("prop_type", child.type_name);
134    }
135
136    #[test]
137    fn child_property_parse_generate_doc() {
138        let r = toml(
139            r#"
140name = "prop"
141type = "prop_type"
142generate_doc = false
143"#,
144        );
145        let child = ChildProperty::parse(&r, "a").unwrap();
146        assert!(!child.generate_doc);
147
148        // Ensure that the default value is "true".
149        let r = toml(
150            r#"
151name = "prop"
152type = "prop_type"
153"#,
154        );
155        let child = ChildProperty::parse(&r, "a").unwrap();
156        assert!(child.generate_doc);
157    }
158
159    #[test]
160    fn child_property_parse_not_all() {
161        let tml = toml(
162            r#"
163name = "prop"
164"#,
165        );
166        assert!(ChildProperty::parse(&tml, "a").is_none());
167
168        let tml = toml(
169            r#"
170type_name = "prop_type"
171"#,
172        );
173        assert!(ChildProperty::parse(&tml, "a").is_none());
174    }
175
176    #[test]
177    fn child_properties_parse() {
178        let toml = toml(
179            r#"
180child_name = "child_name"
181child_type = "child_type"
182[[child_prop]]
183name = "prop"
184type = "prop_type"
185[[child_prop]]
186name = "prop2"
187type = "prop_type2"
188"#,
189        );
190        let props = ChildProperties::parse(&toml, "a").unwrap();
191        assert_eq!(Some("child_name".into()), props.child_name);
192        assert_eq!(Some("child_type".into()), props.child_type);
193        assert_eq!(2, props.properties.len());
194        assert_eq!("prop", props.properties[0].name);
195        assert_eq!("prop_type", props.properties[0].type_name);
196        assert_eq!("prop2", props.properties[1].name);
197        assert_eq!("prop_type2", props.properties[1].type_name);
198    }
199
200    #[test]
201    fn child_property_no_parse_without_children() {
202        let toml = toml(
203            r#"
204child_name = "child_name"
205child_type = "child_type"
206"#,
207        );
208        let props = ChildProperties::parse(&toml, "a");
209        assert!(props.is_none());
210    }
211
212    #[test]
213    fn child_properties_parse_without_child_type_name() {
214        let toml = toml(
215            r#"
216[[child_prop]]
217name = "prop"
218type = "prop_type"
219"#,
220        );
221        let props = ChildProperties::parse(&toml, "a").unwrap();
222        assert_eq!(None, props.child_name);
223        assert_eq!(None, props.child_type);
224        assert_eq!(1, props.properties.len());
225    }
226
227    #[test]
228    fn child_properties_parse_without_child_type() {
229        let toml = toml(
230            r#"
231child_name = "child_name"
232[[child_prop]]
233name = "prop"
234type = "prop_type"
235"#,
236        );
237        let props = ChildProperties::parse(&toml, "a").unwrap();
238        assert_eq!(Some("child_name".into()), props.child_name);
239        assert_eq!(None, props.child_type);
240        assert_eq!(1, props.properties.len());
241    }
242
243    #[test]
244    fn child_properties_parse_without_child_name() {
245        let toml = toml(
246            r#"
247child_type = "child_type"
248[[child_prop]]
249name = "prop"
250type = "prop_type"
251"#,
252        );
253        let props = ChildProperties::parse(&toml, "a").unwrap();
254        assert_eq!(None, props.child_name);
255        assert_eq!(Some("child_type".into()), props.child_type);
256        assert_eq!(1, props.properties.len());
257    }
258}