zbus_xml/
lib.rs

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