rust_qt_binding_generator/
configuration.rs

1use configuration_private::*;
2use serde_json;
3use std::collections::{BTreeMap, BTreeSet};
4use std::error::Error;
5use std::fs;
6use std::path::{Path, PathBuf};
7use std::rc::Rc;
8use toml;
9
10mod json {
11    use super::Rust;
12    use std::collections::BTreeMap;
13    use std::path::PathBuf;
14
15    pub fn false_bool() -> bool {
16        false
17    }
18
19    fn object() -> super::ObjectType {
20        super::ObjectType::Object
21    }
22
23    #[derive(Deserialize)]
24    #[serde(deny_unknown_fields)]
25    pub struct Config {
26        #[serde(rename = "cppFile")]
27        pub cpp_file: PathBuf,
28        pub objects: BTreeMap<String, Object>,
29        pub rust: Rust,
30        #[serde(default = "false_bool")]
31        pub overwrite_implementation: bool,
32    }
33
34    #[derive(Deserialize)]
35    #[serde(deny_unknown_fields)]
36    pub struct Object {
37        #[serde(default)]
38        pub functions: BTreeMap<String, super::Function>,
39        #[serde(rename = "itemProperties", default)]
40        pub item_properties: BTreeMap<String, super::ItemProperty>,
41        #[serde(rename = "type", default = "object")]
42        pub object_type: super::ObjectType,
43        #[serde(default)]
44        pub properties: BTreeMap<String, Property>,
45    }
46
47    #[derive(Deserialize)]
48    #[serde(deny_unknown_fields)]
49    pub struct Property {
50        #[serde(default = "false_bool")]
51        pub optional: bool,
52        #[serde(rename = "type")]
53        pub property_type: String,
54        #[serde(rename = "rustByFunction", default = "false_bool")]
55        pub rust_by_function: bool,
56        #[serde(default = "false_bool")]
57        pub write: bool,
58    }
59}
60
61pub enum RustEdition {
62    Rust2015,
63    Rust2018,
64    Unknown,
65}
66
67impl<'a> ::std::convert::From<Option<&'a str>> for RustEdition {
68    fn from(str: Option<&'a str>) -> RustEdition {
69        match str {
70            None | Some("2015") => RustEdition::Rust2015,
71            Some("2018") => RustEdition::Rust2018,
72            _ => RustEdition::Unknown,
73        }
74    }
75}
76
77pub struct Config {
78    pub config_file: PathBuf,
79    pub cpp_file: PathBuf,
80    pub objects: BTreeMap<String, Rc<Object>>,
81    pub rust: Rust,
82    pub rust_edition: RustEdition,
83    pub overwrite_implementation: bool,
84}
85
86impl ConfigPrivate for Config {
87    fn types(&self) -> BTreeSet<String> {
88        let mut ops = BTreeSet::new();
89        for o in self.objects.values() {
90            for p in o.properties.values() {
91                ops.insert(p.type_name().into());
92            }
93            for p in o.item_properties.values() {
94                ops.insert(p.type_name().into());
95            }
96            for f in o.functions.values() {
97                ops.insert(f.return_type.name().into());
98                for a in &f.arguments {
99                    ops.insert(a.type_name().into());
100                }
101            }
102        }
103        ops
104    }
105    fn optional_types(&self) -> BTreeSet<String> {
106        let mut ops = BTreeSet::new();
107        for o in self.objects.values() {
108            for p in o.properties.values() {
109                if p.optional {
110                    ops.insert(p.type_name().into());
111                }
112            }
113            for p in o.item_properties.values() {
114                if p.optional {
115                    ops.insert(p.type_name().into());
116                }
117            }
118            if o.object_type != ObjectType::Object {
119                ops.insert("quintptr".into());
120            }
121        }
122        ops
123    }
124    fn has_list_or_tree(&self) -> bool {
125        self.objects
126            .values()
127            .any(|o| o.object_type == ObjectType::List || o.object_type == ObjectType::Tree)
128    }
129}
130
131#[derive(PartialEq)]
132pub struct Object {
133    pub name: String,
134    pub functions: BTreeMap<String, Function>,
135    pub item_properties: BTreeMap<String, ItemProperty>,
136    pub object_type: ObjectType,
137    pub properties: BTreeMap<String, Property>,
138}
139
140impl ObjectPrivate for Object {
141    fn contains_object(&self) -> bool {
142        self.properties.values().any(|p| p.is_object())
143    }
144    fn column_count(&self) -> usize {
145        let mut column_count = 1;
146        for ip in self.item_properties.values() {
147            column_count = column_count.max(ip.roles.len());
148        }
149        column_count
150    }
151}
152
153#[derive(PartialEq)]
154pub struct Property {
155    pub optional: bool,
156    pub property_type: Type,
157    pub rust_by_function: bool,
158    pub write: bool,
159}
160
161impl PropertyPrivate for Property {
162    fn is_object(&self) -> bool {
163        self.property_type.is_object()
164    }
165    fn is_complex(&self) -> bool {
166        self.property_type.is_complex()
167    }
168    fn c_get_type(&self) -> String {
169        let name = self.property_type.name();
170        name.to_string() + "*, " + &name.to_lowercase() + "_set"
171    }
172}
173
174impl TypeName for Property {
175    fn type_name(&self) -> &str {
176        self.property_type.name()
177    }
178}
179
180#[derive(Deserialize)]
181#[serde(deny_unknown_fields)]
182pub struct Rust {
183    pub dir: PathBuf,
184    #[serde(rename = "implementationModule")]
185    pub implementation_module: String,
186    #[serde(rename = "interfaceModule")]
187    pub interface_module: String,
188}
189
190#[derive(Deserialize, Clone, Copy, PartialEq)]
191pub enum ObjectType {
192    Object,
193    List,
194    Tree,
195}
196
197#[derive(Deserialize, Clone, Copy, PartialEq)]
198pub enum SimpleType {
199    QString,
200    QByteArray,
201    #[serde(rename = "bool")]
202    Bool,
203    #[serde(rename = "float")]
204    Float,
205    #[serde(rename = "double")]
206    Double,
207    #[serde(rename = "void")]
208    Void,
209    #[serde(rename = "qint8")]
210    Qint8,
211    #[serde(rename = "qint16")]
212    Qint16,
213    #[serde(rename = "qint32")]
214    Qint32,
215    #[serde(rename = "qint64")]
216    Qint64,
217    #[serde(rename = "quint8")]
218    QUint8,
219    #[serde(rename = "quint16")]
220    QUint16,
221    #[serde(rename = "quint32")]
222    QUint32,
223    #[serde(rename = "quint64")]
224    QUint64,
225}
226
227impl SimpleTypePrivate for SimpleType {
228    fn name(&self) -> &str {
229        match self {
230            SimpleType::QString => "QString",
231            SimpleType::QByteArray => "QByteArray",
232            SimpleType::Bool => "bool",
233            SimpleType::Float => "float",
234            SimpleType::Double => "double",
235            SimpleType::Void => "void",
236            SimpleType::Qint8 => "qint8",
237            SimpleType::Qint16 => "qint16",
238            SimpleType::Qint32 => "qint32",
239            SimpleType::Qint64 => "qint64",
240            SimpleType::QUint8 => "quint8",
241            SimpleType::QUint16 => "quint16",
242            SimpleType::QUint32 => "quint32",
243            SimpleType::QUint64 => "quint64",
244        }
245    }
246    fn cpp_set_type(&self) -> &str {
247        match self {
248            SimpleType::QString => "const QString&",
249            SimpleType::QByteArray => "const QByteArray&",
250            _ => self.name(),
251        }
252    }
253    fn c_set_type(&self) -> &str {
254        match self {
255            SimpleType::QString => "qstring_t",
256            SimpleType::QByteArray => "qbytearray_t",
257            _ => self.name(),
258        }
259    }
260    fn rust_type(&self) -> &str {
261        match self {
262            SimpleType::QString => "String",
263            SimpleType::QByteArray => "Vec<u8>",
264            SimpleType::Bool => "bool",
265            SimpleType::Float => "f32",
266            SimpleType::Double => "f64",
267            SimpleType::Void => "()",
268            SimpleType::Qint8 => "i8",
269            SimpleType::Qint16 => "i16",
270            SimpleType::Qint32 => "i32",
271            SimpleType::Qint64 => "i64",
272            SimpleType::QUint8 => "u8",
273            SimpleType::QUint16 => "u16",
274            SimpleType::QUint32 => "u32",
275            SimpleType::QUint64 => "u64",
276        }
277    }
278    fn rust_type_init(&self) -> &str {
279        match self {
280            SimpleType::QString => "String::new()",
281            SimpleType::QByteArray => "Vec::new()",
282            SimpleType::Bool => "false",
283            SimpleType::Float | SimpleType::Double => "0.0",
284            SimpleType::Void => "()",
285            _ => "0",
286        }
287    }
288    fn is_complex(&self) -> bool {
289        self == &SimpleType::QString || self == &SimpleType::QByteArray
290    }
291}
292
293#[derive(PartialEq)]
294pub enum Type {
295    Simple(SimpleType),
296    Object(Rc<Object>),
297}
298
299impl TypePrivate for Type {
300    fn is_object(&self) -> bool {
301        match self {
302            Type::Object(_) => true,
303            _ => false,
304        }
305    }
306    fn is_complex(&self) -> bool {
307        match self {
308            Type::Simple(simple) => simple.is_complex(),
309            _ => false,
310        }
311    }
312    fn name(&self) -> &str {
313        match self {
314            Type::Simple(s) => s.name(),
315            Type::Object(o) => &o.name,
316        }
317    }
318    fn cpp_set_type(&self) -> &str {
319        match self {
320            Type::Simple(s) => s.cpp_set_type(),
321            Type::Object(o) => &o.name,
322        }
323    }
324    fn c_set_type(&self) -> &str {
325        match self {
326            Type::Simple(s) => s.c_set_type(),
327            Type::Object(o) => &o.name,
328        }
329    }
330    fn rust_type(&self) -> &str {
331        match self {
332            Type::Simple(s) => s.rust_type(),
333            Type::Object(o) => &o.name,
334        }
335    }
336    fn rust_type_init(&self) -> &str {
337        match self {
338            Type::Simple(s) => s.rust_type_init(),
339            Type::Object(_) => unimplemented!(),
340        }
341    }
342}
343
344#[derive(Deserialize, Clone, PartialEq)]
345#[serde(deny_unknown_fields)]
346pub struct ItemProperty {
347    #[serde(rename = "type")]
348    pub item_property_type: SimpleType,
349    #[serde(default = "json::false_bool")]
350    pub optional: bool,
351    #[serde(default)]
352    pub roles: Vec<Vec<String>>,
353    #[serde(rename = "rustByValue", default = "json::false_bool")]
354    pub rust_by_value: bool,
355    #[serde(default = "json::false_bool")]
356    pub write: bool,
357}
358
359impl TypeName for ItemProperty {
360    fn type_name(&self) -> &str {
361        self.item_property_type.name()
362    }
363}
364
365impl ItemPropertyPrivate for ItemProperty {
366    fn is_complex(&self) -> bool {
367        self.item_property_type.is_complex()
368    }
369    fn cpp_set_type(&self) -> String {
370        let t = self.item_property_type.cpp_set_type().to_string();
371        if self.optional {
372            return "option_".to_string() + &t;
373        }
374        t
375    }
376    fn c_get_type(&self) -> String {
377        let name = self.item_property_type.name();
378        name.to_string() + "*, " + &name.to_lowercase() + "_set"
379    }
380    fn c_set_type(&self) -> &str {
381        self.item_property_type.c_set_type()
382    }
383}
384
385#[derive(Deserialize, Clone, PartialEq)]
386#[serde(deny_unknown_fields)]
387pub struct Function {
388    #[serde(rename = "return")]
389    pub return_type: SimpleType,
390    #[serde(rename = "mut", default = "json::false_bool")]
391    pub mutable: bool,
392    #[serde(default)]
393    pub arguments: Vec<Argument>,
394}
395
396impl TypeName for Function {
397    fn type_name(&self) -> &str {
398        self.return_type.name()
399    }
400}
401
402#[derive(Deserialize, Clone, PartialEq)]
403#[serde(deny_unknown_fields)]
404pub struct Argument {
405    pub name: String,
406    #[serde(rename = "type")]
407    pub argument_type: SimpleType,
408}
409
410impl TypeName for Argument {
411    fn type_name(&self) -> &str {
412        self.argument_type.name()
413    }
414}
415
416fn post_process_property(
417    a: (&String, &json::Property),
418    b: &mut BTreeMap<String, Rc<Object>>,
419    c: &BTreeMap<String, json::Object>,
420) -> Result<Property, Box<dyn Error>> {
421    let name = &a.1.property_type;
422    let t = match serde_json::from_str::<SimpleType>(&format!("\"{}\"", name)) {
423        Err(_) => {
424            if b.get(name).is_none() {
425                if let Some(object) = c.get(name) {
426                    post_process_object((name, object), b, c)?;
427                } else {
428                    return Err(format!("Type {} cannot be found.", name).into());
429                }
430            }
431            Type::Object(Rc::clone(b.get(name).unwrap()))
432        }
433        Ok(simple) => Type::Simple(simple),
434    };
435    Ok(Property {
436        property_type: t,
437        optional: a.1.optional,
438        rust_by_function: a.1.rust_by_function,
439        write: a.1.write,
440    })
441}
442
443fn post_process_object(
444    a: (&String, &json::Object),
445    b: &mut BTreeMap<String, Rc<Object>>,
446    c: &BTreeMap<String, json::Object>,
447) -> Result<(), Box<dyn Error>> {
448    let mut properties = BTreeMap::default();
449    for p in &a.1.properties {
450        properties.insert(p.0.clone(), post_process_property(p, b, c)?);
451    }
452    let object = Rc::new(Object {
453        name: a.0.clone(),
454        object_type: a.1.object_type,
455        functions: a.1.functions.clone(),
456        item_properties: a.1.item_properties.clone(),
457        properties,
458    });
459    b.insert(a.0.clone(), object);
460    Ok(())
461}
462
463fn post_process(config_file: &Path, json: json::Config) -> Result<Config, Box<dyn Error>> {
464    let mut objects = BTreeMap::default();
465    for object in &json.objects {
466        post_process_object(object, &mut objects, &json.objects)?;
467    }
468
469    let rust_edition: RustEdition = {
470        let mut buf = config_file.to_path_buf();
471        buf.pop();
472        buf.push(&json.rust.dir);
473        buf.push("Cargo.toml");
474        if !buf.exists() {
475            return Err(format!("{} does not exist.", buf.display()).into());
476        }
477        let manifest: toml::Value = fs::read_to_string(&buf)?.parse()?;
478        manifest["package"]
479            .get("edition")
480            .and_then(|val| val.as_str())
481            .into()
482    };
483
484    Ok(Config {
485        config_file: config_file.into(),
486        cpp_file: json.cpp_file,
487        objects,
488        rust: json.rust,
489        rust_edition,
490        overwrite_implementation: json.overwrite_implementation,
491    })
492}
493
494pub fn parse<P: AsRef<Path>>(config_file: P) -> Result<Config, Box<dyn Error>> {
495    let contents = fs::read_to_string(config_file.as_ref())?;
496    let config: json::Config = serde_json::from_str(&contents)?;
497    post_process(config_file.as_ref(), config)
498}