zbus_xml/
lib.rs

1#![deny(rust_2018_idioms)]
2#![doc(
3    html_logo_url = "https://storage.googleapis.com/fdo-gitlab-uploads/project/avatar/3213/zbus-logomark.png"
4)]
5#![doc = include_str!("../README.md")]
6#![doc(test(attr(
7    warn(unused),
8    deny(warnings),
9    // W/o this, we seem to get some bogus warning about `extern crate zbus`.
10    allow(unused_extern_crates),
11)))]
12
13mod error;
14pub use error::{Error, Result};
15
16use quick_xml::{de::Deserializer, se::to_writer};
17use serde::{Deserialize, Serialize};
18use static_assertions::assert_impl_all;
19use std::io::{BufReader, Read, Write};
20
21use zbus_names::{InterfaceName, MemberName, PropertyName};
22use zvariant::CompleteType;
23
24/// Annotations are generic key/value pairs of metadata.
25#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
26pub struct Annotation {
27    #[serde(rename = "@name")]
28    name: String,
29    #[serde(rename = "@value")]
30    value: String,
31}
32
33assert_impl_all!(Annotation: Send, Sync, Unpin);
34
35impl Annotation {
36    /// Return the annotation name/key.
37    pub fn name(&self) -> &str {
38        &self.name
39    }
40
41    /// Return the annotation value.
42    pub fn value(&self) -> &str {
43        &self.value
44    }
45}
46
47/// A direction of an argument
48#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
49pub enum ArgDirection {
50    #[serde(rename = "in")]
51    In,
52    #[serde(rename = "out")]
53    Out,
54}
55
56/// An argument
57#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
58pub struct Arg<'a> {
59    #[serde(rename = "@name")]
60    name: Option<String>,
61    #[serde(rename = "@type", borrow)]
62    ty: CompleteType<'a>,
63    #[serde(rename = "@direction")]
64    direction: Option<ArgDirection>,
65    #[serde(rename = "annotation", default)]
66    annotations: Vec<Annotation>,
67}
68
69assert_impl_all!(Arg<'_>: Send, Sync, Unpin);
70
71impl<'a> Arg<'a> {
72    /// Return the argument name, if any.
73    pub fn name(&self) -> Option<&str> {
74        self.name.as_deref()
75    }
76
77    /// Return the argument type.
78    pub fn ty(&self) -> &CompleteType<'a> {
79        &self.ty
80    }
81
82    /// Return the argument direction, if any.
83    pub fn direction(&self) -> Option<ArgDirection> {
84        self.direction
85    }
86
87    /// Return the associated annotations.
88    pub fn annotations(&self) -> &[Annotation] {
89        &self.annotations
90    }
91}
92
93/// A method
94#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
95pub struct Method<'a> {
96    #[serde(rename = "@name", borrow)]
97    name: MemberName<'a>,
98    #[serde(rename = "arg", default, borrow)]
99    args: Vec<Arg<'a>>,
100    #[serde(rename = "annotation", default)]
101    annotations: Vec<Annotation>,
102}
103
104assert_impl_all!(Method<'_>: Send, Sync, Unpin);
105
106impl<'a> Method<'a> {
107    /// Return the method name.
108    pub fn name(&self) -> MemberName<'_> {
109        self.name.as_ref()
110    }
111
112    /// Return the method arguments.
113    pub fn args(&self) -> &[Arg<'a>] {
114        &self.args
115    }
116
117    /// Return the method annotations.
118    pub fn annotations(&self) -> &[Annotation] {
119        &self.annotations
120    }
121}
122
123/// A signal
124#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
125pub struct Signal<'a> {
126    #[serde(rename = "@name", borrow)]
127    name: MemberName<'a>,
128
129    #[serde(rename = "arg", default)]
130    args: Vec<Arg<'a>>,
131    #[serde(rename = "annotation", default)]
132    annotations: Vec<Annotation>,
133}
134
135assert_impl_all!(Signal<'_>: Send, Sync, Unpin);
136
137impl<'a> Signal<'a> {
138    /// Return the signal name.
139    pub fn name(&self) -> MemberName<'_> {
140        self.name.as_ref()
141    }
142
143    /// Return the signal arguments.
144    pub fn args(&self) -> &[Arg<'a>] {
145        &self.args
146    }
147
148    /// Return the signal annotations.
149    pub fn annotations(&self) -> &[Annotation] {
150        &self.annotations
151    }
152}
153
154/// The possible property access types
155#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
156pub enum PropertyAccess {
157    #[serde(rename = "read")]
158    Read,
159    #[serde(rename = "write")]
160    Write,
161    #[serde(rename = "readwrite")]
162    ReadWrite,
163}
164
165impl PropertyAccess {
166    pub fn read(&self) -> bool {
167        matches!(self, PropertyAccess::Read | PropertyAccess::ReadWrite)
168    }
169
170    pub fn write(&self) -> bool {
171        matches!(self, PropertyAccess::Write | PropertyAccess::ReadWrite)
172    }
173}
174
175/// A property
176#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
177pub struct Property<'a> {
178    #[serde(rename = "@name", borrow)]
179    name: PropertyName<'a>,
180
181    #[serde(rename = "@type")]
182    ty: CompleteType<'a>,
183    #[serde(rename = "@access")]
184    access: PropertyAccess,
185
186    #[serde(rename = "annotation", default)]
187    annotations: Vec<Annotation>,
188}
189
190assert_impl_all!(Property<'_>: Send, Sync, Unpin);
191
192impl<'a> Property<'a> {
193    /// Returns the property name.
194    pub fn name(&self) -> PropertyName<'_> {
195        self.name.as_ref()
196    }
197
198    /// Returns the property type.
199    pub fn ty(&self) -> &CompleteType<'a> {
200        &self.ty
201    }
202
203    /// Returns the property access flags (should be "read", "write" or "readwrite").
204    pub fn access(&self) -> PropertyAccess {
205        self.access
206    }
207
208    /// Return the associated annotations.
209    pub fn annotations(&self) -> &[Annotation] {
210        &self.annotations
211    }
212}
213
214/// An interface
215#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
216pub struct Interface<'a> {
217    #[serde(rename = "@name", borrow)]
218    name: InterfaceName<'a>,
219
220    #[serde(rename = "method", default)]
221    methods: Vec<Method<'a>>,
222    #[serde(rename = "property", default)]
223    properties: Vec<Property<'a>>,
224    #[serde(rename = "signal", default)]
225    signals: Vec<Signal<'a>>,
226    #[serde(rename = "annotation", default)]
227    annotations: Vec<Annotation>,
228}
229
230assert_impl_all!(Interface<'_>: Send, Sync, Unpin);
231
232impl<'a> Interface<'a> {
233    /// Returns the interface name.
234    pub fn name(&self) -> InterfaceName<'_> {
235        self.name.as_ref()
236    }
237
238    /// Returns the interface methods.
239    pub fn methods(&self) -> &[Method<'a>] {
240        &self.methods
241    }
242
243    /// Returns the interface signals.
244    pub fn signals(&self) -> &[Signal<'a>] {
245        &self.signals
246    }
247
248    /// Returns the interface properties.
249    pub fn properties(&self) -> &[Property<'_>] {
250        &self.properties
251    }
252
253    /// Return the associated annotations.
254    pub fn annotations(&self) -> &[Annotation] {
255        &self.annotations
256    }
257}
258
259/// An introspection tree node (typically the root of the XML document).
260#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
261pub struct Node<'a> {
262    #[serde(rename = "@name")]
263    name: Option<String>,
264
265    #[serde(rename = "interface", default, borrow)]
266    interfaces: Vec<Interface<'a>>,
267    #[serde(rename = "node", default, borrow)]
268    nodes: Vec<Node<'a>>,
269}
270
271assert_impl_all!(Node<'_>: Send, Sync, Unpin);
272
273impl<'a> Node<'a> {
274    /// Parse the introspection XML document from reader.
275    pub fn from_reader<R: Read>(reader: R) -> Result<Node<'a>> {
276        let mut deserializer = Deserializer::from_reader(BufReader::new(reader));
277        deserializer.event_buffer_size(Some(1024_usize.try_into().unwrap()));
278        Ok(Node::deserialize(&mut deserializer)?)
279    }
280
281    /// Write the XML document to writer.
282    pub fn to_writer<W: Write>(&self, writer: W) -> Result<()> {
283        // Need this wrapper until this is resolved: https://github.com/tafia/quick-xml/issues/499
284        struct Writer<T>(T);
285
286        impl<T> std::fmt::Write for Writer<T>
287        where
288            T: Write,
289        {
290            fn write_str(&mut self, s: &str) -> std::fmt::Result {
291                self.0.write_all(s.as_bytes()).map_err(|_| std::fmt::Error)
292            }
293        }
294
295        to_writer(Writer(writer), &self)?;
296
297        Ok(())
298    }
299
300    /// Returns the node name, if any.
301    pub fn name(&self) -> Option<&str> {
302        self.name.as_deref()
303    }
304
305    /// Returns the children nodes.
306    pub fn nodes(&self) -> &[Node<'a>] {
307        &self.nodes
308    }
309
310    /// Returns the interfaces on this node.
311    pub fn interfaces(&self) -> &[Interface<'a>] {
312        &self.interfaces
313    }
314}
315
316impl<'a> TryFrom<&'a str> for Node<'a> {
317    type Error = Error;
318
319    /// Parse the introspection XML document from `s`.
320    fn try_from(s: &'a str) -> Result<Node<'a>> {
321        let mut deserializer = Deserializer::from_str(s);
322        deserializer.event_buffer_size(Some(1024_usize.try_into().unwrap()));
323        Ok(Node::deserialize(&mut deserializer)?)
324    }
325}