Skip to main content

zbus_xml/
lib.rs

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