rustnetconf_yang/
serialize.rs1use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
8use quick_xml::Writer;
9use std::io::Cursor;
10
11pub trait ToNetconfXml {
15 fn namespace(&self) -> &str;
17
18 fn root_element(&self) -> &str;
20
21 fn to_xml(&self) -> Result<String, XmlError>;
23}
24
25pub trait FromNetconfXml: Sized {
27 fn from_xml(xml: &str) -> Result<Self, XmlError>;
29}
30
31#[derive(Debug, thiserror::Error)]
33pub enum XmlError {
34 #[error("XML write error: {0}")]
35 Write(String),
36
37 #[error("XML parse error: {0}")]
38 Parse(String),
39
40 #[error("missing required field: {0}")]
41 MissingField(String),
42
43 #[error("invalid value for field '{field}': {message}")]
44 InvalidValue { field: String, message: String },
45}
46
47pub fn write_text_element(
49 writer: &mut Writer<Cursor<Vec<u8>>>,
50 name: &str,
51 value: &str,
52) -> Result<(), XmlError> {
53 let start = BytesStart::new(name);
54 writer
55 .write_event(Event::Start(start))
56 .map_err(|e| XmlError::Write(e.to_string()))?;
57 writer
58 .write_event(Event::Text(BytesText::new(value)))
59 .map_err(|e| XmlError::Write(e.to_string()))?;
60 writer
61 .write_event(Event::End(BytesEnd::new(name)))
62 .map_err(|e| XmlError::Write(e.to_string()))?;
63 Ok(())
64}
65
66pub fn write_start_with_ns(
68 writer: &mut Writer<Cursor<Vec<u8>>>,
69 name: &str,
70 namespace: &str,
71) -> Result<(), XmlError> {
72 let mut start = BytesStart::new(name);
73 start.push_attribute(("xmlns", namespace));
74 writer
75 .write_event(Event::Start(start))
76 .map_err(|e| XmlError::Write(e.to_string()))?;
77 Ok(())
78}
79
80pub fn write_end(
82 writer: &mut Writer<Cursor<Vec<u8>>>,
83 name: &str,
84) -> Result<(), XmlError> {
85 writer
86 .write_event(Event::End(BytesEnd::new(name)))
87 .map_err(|e| XmlError::Write(e.to_string()))?;
88 Ok(())
89}
90
91pub fn new_writer() -> Writer<Cursor<Vec<u8>>> {
93 Writer::new_with_indent(Cursor::new(Vec::new()), b' ', 2)
94}
95
96pub fn finish_writer(writer: Writer<Cursor<Vec<u8>>>) -> Result<String, XmlError> {
98 let buf = writer.into_inner().into_inner();
99 String::from_utf8(buf).map_err(|e| XmlError::Write(e.to_string()))
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn test_write_text_element() {
108 let mut writer = new_writer();
109 write_text_element(&mut writer, "host-name", "spine-01").unwrap();
110 let xml = finish_writer(writer).unwrap();
111 assert_eq!(xml, "<host-name>spine-01</host-name>");
112 }
113
114 #[test]
115 fn test_write_start_with_ns() {
116 let mut writer = new_writer();
117 write_start_with_ns(&mut writer, "interfaces", "urn:ietf:params:xml:ns:yang:ietf-interfaces").unwrap();
118 write_end(&mut writer, "interfaces").unwrap();
119 let xml = finish_writer(writer).unwrap();
120 assert!(xml.contains("xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\""));
121 }
122}