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}