libgir/config/
properties.rs

1use log::error;
2use toml::Value;
3
4use super::{
5    error::TomlHelper, gobjects::GStatus, ident::Ident, parsable::Parse,
6    property_generate_flags::PropertyGenerateFlags,
7};
8use crate::version::Version;
9
10#[derive(Clone, Debug)]
11pub struct Property {
12    pub ident: Ident,
13    pub status: GStatus,
14    pub version: Option<Version>,
15    pub generate: Option<PropertyGenerateFlags>,
16    pub bypass_auto_rename: bool,
17    pub doc_trait_name: Option<String>,
18    pub generate_doc: bool,
19}
20
21impl Parse for Property {
22    fn parse(toml: &Value, object_name: &str) -> Option<Self> {
23        let Some(ident) = Ident::parse(toml, object_name, "property") else {
24            error!(
25                "No 'name' or 'pattern' given for property for object {}",
26                object_name
27            );
28            return None;
29        };
30
31        toml.check_unwanted(
32            &[
33                "ignore",
34                "manual",
35                "version",
36                "name",
37                "pattern",
38                "generate",
39                "bypass_auto_rename",
40                "doc_trait_name",
41                "generate_doc",
42            ],
43            &format!("property {object_name}"),
44        );
45
46        let status = {
47            if toml
48                .lookup("ignore")
49                .and_then(Value::as_bool)
50                .unwrap_or(false)
51            {
52                GStatus::Ignore
53            } else if toml
54                .lookup("manual")
55                .and_then(Value::as_bool)
56                .unwrap_or(false)
57            {
58                GStatus::Manual
59            } else {
60                GStatus::Generate
61            }
62        };
63        let version = toml
64            .lookup("version")
65            .and_then(Value::as_str)
66            .and_then(|s| s.parse().ok());
67        let generate = toml.lookup("generate").and_then(|v| {
68            PropertyGenerateFlags::parse_flags(v, "generate")
69                .map_err(|e| error!("{} for object {}", e, object_name))
70                .ok()
71        });
72        let bypass_auto_rename = toml
73            .lookup("bypass_auto_rename")
74            .and_then(Value::as_bool)
75            .unwrap_or(false);
76        let doc_trait_name = toml
77            .lookup("doc_trait_name")
78            .and_then(Value::as_str)
79            .map(ToOwned::to_owned);
80        let generate_doc = toml
81            .lookup("generate_doc")
82            .and_then(Value::as_bool)
83            .unwrap_or(true);
84
85        Some(Self {
86            ident,
87            status,
88            version,
89            generate,
90            bypass_auto_rename,
91            doc_trait_name,
92            generate_doc,
93        })
94    }
95}
96
97impl AsRef<Ident> for Property {
98    fn as_ref(&self) -> &Ident {
99        &self.ident
100    }
101}
102
103pub type Properties = Vec<Property>;
104
105#[cfg(test)]
106mod tests {
107    use super::{
108        super::{
109            ident::Ident,
110            matchable::Matchable,
111            parsable::{Parsable, Parse},
112        },
113        *,
114    };
115    use crate::version::Version;
116
117    fn properties_toml(input: &str) -> ::toml::Value {
118        let mut value: ::toml::value::Table = ::toml::from_str(input).unwrap();
119        value.remove("f").unwrap()
120    }
121
122    fn toml(input: &str) -> ::toml::Value {
123        let value = input.parse();
124        assert!(value.is_ok());
125        value.unwrap()
126    }
127
128    #[test]
129    fn property_parse_ignore() {
130        let toml = toml(
131            r#"
132name = "prop1"
133ignore = true
134"#,
135        );
136        let p = Property::parse(&toml, "a").unwrap();
137        assert_eq!(p.ident, Ident::Name("prop1".into()));
138        assert!(p.status.ignored());
139    }
140
141    #[test]
142    fn property_parse_manual() {
143        let toml = toml(
144            r#"
145name = "prop1"
146manual = true
147"#,
148        );
149        let p = Property::parse(&toml, "a").unwrap();
150        assert_eq!(p.ident, Ident::Name("prop1".into()));
151        assert!(p.status.manual());
152    }
153
154    #[test]
155    fn property_bypass_auto_rename() {
156        let toml = toml(
157            r#"
158name = "prop1"
159bypass_auto_rename = true
160"#,
161        );
162        let f = Property::parse(&toml, "a").unwrap();
163        assert_eq!(f.ident, Ident::Name("prop1".into()));
164        assert!(f.bypass_auto_rename);
165    }
166
167    #[test]
168    fn property_parse_version_default() {
169        let toml = toml(
170            r#"
171name = "prop1"
172"#,
173        );
174        let p = Property::parse(&toml, "a").unwrap();
175        assert_eq!(p.version, None);
176        assert!(p.status.need_generate());
177    }
178
179    #[test]
180    fn property_parse_version() {
181        let toml = toml(
182            r#"
183name = "prop1"
184version = "3.20"
185"#,
186        );
187        let p = Property::parse(&toml, "a").unwrap();
188        assert_eq!(p.version, Some(Version::new(3, 20, 0)));
189    }
190
191    #[test]
192    fn property_generate_doc() {
193        let r = toml(
194            r#"
195name = "prop"
196generate_doc = false
197"#,
198        );
199        let p = Property::parse(&r, "a").unwrap();
200        assert!(!p.generate_doc);
201
202        // Ensure that the default value is "true".
203        let r = toml(
204            r#"
205name = "prop"
206"#,
207        );
208        let p = Property::parse(&r, "a").unwrap();
209        assert!(p.generate_doc);
210    }
211
212    #[test]
213    fn properties_parse_empty_for_none() {
214        let props = Properties::parse(None, "a");
215        assert!(props.is_empty());
216    }
217
218    #[test]
219    fn properties_parse_matches() {
220        let toml = properties_toml(
221            r#"
222[[f]]
223name = "prop1"
224[[f]]
225name = "p1.5"
226[[f]]
227name = "prop2"
228[[f]]
229pattern = 'prop\d+'
230"#,
231        );
232        let props = Properties::parse(Some(&toml), "a");
233        assert_eq!(props.len(), 3);
234
235        assert_eq!(props.matched("prop1").len(), 2);
236        assert_eq!(props.matched("prop2").len(), 2);
237        assert_eq!(props.matched("prop3").len(), 1);
238        // "p1.5" is an invalid name
239        assert_eq!(props.matched("p1.5").len(), 0);
240        assert_eq!(props.matched("none").len(), 0);
241    }
242}