Skip to content

Commit 2d20fe0

Browse files
Add support for nested models to yaserde (#10)
* Add support for nested models to yaserde Signed-off-by: Luca Della Vedova <[email protected]> * Add From for boxed Signed-off-by: Luca Della Vedova <[email protected]> --------- Signed-off-by: Luca Della Vedova <[email protected]>
1 parent 89af643 commit 2d20fe0

File tree

3 files changed

+109
-17
lines changed

3 files changed

+109
-17
lines changed

sdformat_rs/build.rs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ struct SDFAttribute {
8181
required: RequiredStatus,
8282
default: Option<String>,
8383
description: String,
84+
reference: Option<String>,
8485
}
8586

8687
impl SDFAttribute {
@@ -91,6 +92,7 @@ impl SDFAttribute {
9192
required: RequiredStatus::Optional,
9293
default: None,
9394
description: "".to_string(),
95+
reference: None,
9496
}
9597
}
9698
fn get_field_string(&self) -> String {
@@ -130,6 +132,7 @@ impl SDFElement {
130132
required: RequiredStatus::Optional,
131133
default: None,
132134
description: "".to_string(),
135+
reference: None,
133136
},
134137
child_elems: vec![],
135138
child_attrs: vec![],
@@ -160,25 +163,26 @@ impl SDFElement {
160163
}
161164
out += "#[derive(Default, PartialEq, Clone, Debug, YaSerialize, YaDeserialize)]\n";
162165
out += format!("#[yaserde(rename = \"{}\")]\n", self.properties.name).as_str();
163-
if self.top_level {
164-
out += format!("pub struct {}{} {{\n", prefix_type(prefix), self.typename()).as_str();
165-
} else {
166-
out += format!(
167-
"pub struct {}{} {{\n",
168-
prefix_type(prefix),
169-
self.properties.name.to_case(Case::Pascal)
170-
)
171-
.as_str();
172-
}
166+
out += format!("pub struct {}{} {{\n", prefix_type(prefix), self.typename()).as_str();
173167
for child in &self.child_attrs {
174168
out += child.get_field_string().as_str();
175169
}
176170

177171
let mut child_gen = "".to_string();
178-
let name = prefix.to_string().to_case(Case::Pascal) + self.properties.name.as_str();
172+
let name = prefix.to_string().to_case(Case::Pascal) + self.typename().as_str();
179173
for child in &self.child_elems {
180174
if child.properties.rtype.is_empty() {
181175
// TODO(arjo): Handle includes
176+
if let Some(reference) = &child.properties.reference {
177+
out += format!(
178+
" #[yaserde(child, rename = \"{}\")]\n pub {}: Vec<Boxed<Sdf{}>>,\n",
179+
reference,
180+
reference,
181+
self.typename()
182+
)
183+
.as_str();
184+
continue;
185+
}
182186
let prefix = prefix_type(&name);
183187
child_gen += child.code_gen(prefix.as_str(), file_map).as_str();
184188
let typename = prefix + child.properties.name.to_case(Case::Pascal).as_str();
@@ -251,6 +255,9 @@ fn parse_element(model: &mut SDFElement, element: &Element) {
251255
if let Some(required) = element.attributes.get("required") {
252256
model.properties.required = RequiredStatus::from_str(required);
253257
}
258+
if let Some(reference) = element.attributes.get("ref") {
259+
model.properties.reference = Some(reference.clone());
260+
}
254261
} else if element.name == "attribute" {
255262
let mut attr = SDFAttribute::new();
256263
// Parse element description
@@ -282,12 +289,9 @@ fn parse_element(model: &mut SDFElement, element: &Element) {
282289
if el.name == "attribute" {
283290
parse_element(model, el);
284291
} else if el.name == "element" {
285-
if el.attributes.contains_key("ref") {
286-
} else {
287-
let mut elem = SDFElement::new();
288-
parse_element(&mut elem, el);
289-
model.child_elems.push(elem);
290-
}
292+
let mut elem = SDFElement::new();
293+
parse_element(&mut elem, el);
294+
model.child_elems.push(elem);
291295
} else if el.name == "include" {
292296
let incl = SDFIncludes {
293297
filename: el.attributes.get("filename").unwrap().to_string(),

sdformat_rs/src/lib.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
extern crate yaserde_derive;
22
use std::collections::{BTreeSet, HashMap};
3+
use std::fmt::Debug;
34
use std::io::{Read, Write};
5+
use std::ops::{Deref, DerefMut};
46
use std::sync::Arc;
57

68
use nalgebra::*;
@@ -14,6 +16,83 @@ use yaserde_derive::{YaDeserialize, YaSerialize};
1416
// Most of the structs are generated automatically from the
1517
include!(concat!(env!("OUT_DIR"), "/sdf.rs"));
1618

19+
pub struct Boxed<T> {
20+
inner: Box<T>,
21+
}
22+
23+
impl<T> From<T> for Boxed<T> {
24+
fn from(t: T) -> Self {
25+
Self {
26+
inner: Box::new(t),
27+
}
28+
}
29+
}
30+
31+
impl<T: PartialEq> PartialEq for Boxed<T> {
32+
fn eq(&self, rhs: &Self) -> bool {
33+
self.inner == rhs.inner
34+
}
35+
}
36+
37+
impl<T: YaDeserialize> YaDeserialize for Boxed<T> {
38+
fn deserialize<R: Read>(reader: &mut yaserde::de::Deserializer<R>) -> Result<Self, String> {
39+
Ok(Self {
40+
inner: Box::new(T::deserialize(reader)?),
41+
})
42+
}
43+
}
44+
45+
impl<T: YaSerialize> YaSerialize for Boxed<T> {
46+
fn serialize<W: Write>(&self, writer: &mut yaserde::ser::Serializer<W>) -> Result<(), String> {
47+
self.inner.as_ref().serialize(writer)
48+
}
49+
50+
fn serialize_attributes(
51+
&self,
52+
attributes: Vec<OwnedAttribute>,
53+
namespace: Namespace,
54+
) -> Result<(Vec<OwnedAttribute>, Namespace), String> {
55+
self.inner
56+
.as_ref()
57+
.serialize_attributes(attributes, namespace)
58+
}
59+
}
60+
61+
impl<T: Default> Default for Boxed<T> {
62+
fn default() -> Self {
63+
Self {
64+
inner: Default::default(),
65+
}
66+
}
67+
}
68+
69+
impl<T: Clone> Clone for Boxed<T> {
70+
fn clone(&self) -> Self {
71+
Self {
72+
inner: self.inner.clone(),
73+
}
74+
}
75+
}
76+
77+
impl<T: Debug> Debug for Boxed<T> {
78+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79+
self.inner.as_ref().fmt(f)
80+
}
81+
}
82+
83+
impl<T> Deref for Boxed<T> {
84+
type Target = T;
85+
fn deref(&self) -> &Self::Target {
86+
&self.inner
87+
}
88+
}
89+
90+
impl<T> DerefMut for Boxed<T> {
91+
fn deref_mut(&mut self) -> &mut Self::Target {
92+
&mut self.inner
93+
}
94+
}
95+
1796
#[derive(PartialEq, Clone, Debug)]
1897
pub enum ElementData {
1998
String(String),

sdformat_rs/tests/camera_test.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,12 @@ fn test_light_direction_pose_serdeser() {
102102
let serialized = yaserde::ser::to_string(&fr.unwrap()).unwrap();
103103
assert_eq!(test_syntax.to_string(), serialized);
104104
}
105+
106+
use sdformat_rs::SdfModel;
107+
#[test]
108+
fn test_nested_model() {
109+
let test_syntax = "<?xml version=\"1.0\" encoding=\"utf-8\"?><model name=\"top\"><model name=\"nested\" /></model>";
110+
let fr = from_str::<SdfModel>(test_syntax);
111+
let serialized = yaserde::ser::to_string(&fr.unwrap()).unwrap();
112+
assert_eq!(test_syntax.to_string(), serialized);
113+
}

0 commit comments

Comments
 (0)