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 allow(unused_extern_crates),
12)))]
13
14mod error;
15#[allow(deprecated)]
16pub use error::{DeError, SeError};
17pub use error::{Error, Result, XmlError};
18
19mod xml;
20use xml::escape;
21
22pub mod telepathy;
23
24use serde::{Deserialize, Serialize};
25use std::{
26 fmt,
27 io::{BufWriter, Read, Write},
28 ops::Deref,
29};
30
31use zbus_names::{InterfaceName, MemberName, PropertyName};
32
33#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct Warning {
44 element: String,
45 position: usize,
46 message: String,
47}
48
49impl Warning {
50 pub(crate) fn unsupported(element: impl Into<String>, position: usize) -> Self {
52 let element = element.into();
53 let message = format!("unsupported element `<{element}>` ignored");
54 Self {
55 element,
56 position,
57 message,
58 }
59 }
60
61 pub(crate) fn malformed(
63 element: impl Into<String>,
64 position: usize,
65 reason: impl fmt::Display,
66 ) -> Self {
67 let element = element.into();
68 let message = format!("malformed element `<{element}>` ignored: {reason}");
69 Self {
70 element,
71 position,
72 message,
73 }
74 }
75
76 pub fn element(&self) -> &str {
78 &self.element
79 }
80
81 pub fn position(&self) -> usize {
83 self.position
84 }
85
86 pub fn message(&self) -> &str {
88 &self.message
89 }
90}
91
92impl fmt::Display for Warning {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 write!(f, "{} (at byte offset {})", self.message, self.position)
95 }
96}
97
98#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
100pub struct Annotation {
101 #[serde(rename = "@name")]
102 name: String,
103 #[serde(rename = "@value")]
104 value: String,
105}
106
107impl Annotation {
108 pub fn name(&self) -> &str {
110 &self.name
111 }
112
113 pub fn value(&self) -> &str {
115 &self.value
116 }
117
118 fn write_xml<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
119 write!(
120 w,
121 "<annotation name=\"{}\" value=\"{}\"/>",
122 escape(&self.name),
123 escape(&self.value)
124 )
125 }
126}
127
128#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
130pub enum ArgDirection {
131 #[serde(rename = "in")]
132 In,
133 #[serde(rename = "out")]
134 Out,
135}
136
137impl ArgDirection {
138 fn xml_value(&self) -> &'static str {
139 match self {
140 ArgDirection::In => "in",
141 ArgDirection::Out => "out",
142 }
143 }
144}
145
146#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
148pub struct Arg {
149 #[serde(rename = "@name")]
150 name: Option<String>,
151 #[serde(rename = "@type")]
152 ty: Signature,
153 #[serde(rename = "@direction")]
154 direction: Option<ArgDirection>,
155 #[serde(rename = "annotation", default)]
156 annotations: Vec<Annotation>,
157 #[serde(skip)]
158 docstring: Option<String>,
159 #[serde(skip)]
160 tp_type: Option<String>,
161}
162
163impl Arg {
164 pub fn name(&self) -> Option<&str> {
166 self.name.as_deref()
167 }
168
169 pub fn ty(&self) -> &Signature {
171 &self.ty
172 }
173
174 pub fn direction(&self) -> Option<ArgDirection> {
176 self.direction
177 }
178
179 pub fn annotations(&self) -> &[Annotation] {
181 &self.annotations
182 }
183
184 pub fn docstring(&self) -> Option<&str> {
190 self.docstring.as_deref()
191 }
192
193 pub fn tp_type(&self) -> Option<&str> {
198 self.tp_type.as_deref()
199 }
200
201 fn write_xml<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
202 write!(w, "<arg")?;
203 if let Some(name) = &self.name {
204 write!(w, " name=\"{}\"", escape(name))?;
205 }
206 write!(w, " type=\"{}\"", escape(&self.ty.to_string()))?;
207 if let Some(direction) = self.direction {
208 write!(w, " direction=\"{}\"", direction.xml_value())?;
209 }
210 if self.annotations.is_empty() {
211 return write!(w, "/>");
212 }
213 write!(w, ">")?;
214 for annotation in &self.annotations {
215 annotation.write_xml(w)?;
216 }
217 write!(w, "</arg>")
218 }
219}
220
221#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
223pub struct Method<'a> {
224 #[serde(rename = "@name", borrow)]
225 name: MemberName<'a>,
226 #[serde(rename = "arg", default)]
227 args: Vec<Arg>,
228 #[serde(rename = "annotation", default)]
229 annotations: Vec<Annotation>,
230 #[serde(skip)]
231 docstring: Option<String>,
232}
233
234impl Method<'_> {
235 pub fn name(&self) -> MemberName<'_> {
237 self.name.as_ref()
238 }
239
240 pub fn args(&self) -> &[Arg] {
242 &self.args
243 }
244
245 pub fn annotations(&self) -> &[Annotation] {
247 &self.annotations
248 }
249
250 pub fn docstring(&self) -> Option<&str> {
256 self.docstring.as_deref()
257 }
258
259 fn write_xml<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
260 write!(w, "<method name=\"{}\"", escape(self.name.as_str()))?;
261 if self.args.is_empty() && self.annotations.is_empty() {
262 return write!(w, "/>");
263 }
264 write!(w, ">")?;
265 for arg in &self.args {
266 arg.write_xml(w)?;
267 }
268 for annotation in &self.annotations {
269 annotation.write_xml(w)?;
270 }
271 write!(w, "</method>")
272 }
273}
274
275#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
277pub struct Signal<'a> {
278 #[serde(rename = "@name", borrow)]
279 name: MemberName<'a>,
280
281 #[serde(rename = "arg", default)]
282 args: Vec<Arg>,
283 #[serde(rename = "annotation", default)]
284 annotations: Vec<Annotation>,
285 #[serde(skip)]
286 docstring: Option<String>,
287}
288
289impl Signal<'_> {
290 pub fn name(&self) -> MemberName<'_> {
292 self.name.as_ref()
293 }
294
295 pub fn args(&self) -> &[Arg] {
297 &self.args
298 }
299
300 pub fn annotations(&self) -> &[Annotation] {
302 &self.annotations
303 }
304
305 pub fn docstring(&self) -> Option<&str> {
311 self.docstring.as_deref()
312 }
313
314 fn write_xml<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
315 write!(w, "<signal name=\"{}\"", escape(self.name.as_str()))?;
316 if self.args.is_empty() && self.annotations.is_empty() {
317 return write!(w, "/>");
318 }
319 write!(w, ">")?;
320 for arg in &self.args {
321 arg.write_xml(w)?;
322 }
323 for annotation in &self.annotations {
324 annotation.write_xml(w)?;
325 }
326 write!(w, "</signal>")
327 }
328}
329
330#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
332pub enum PropertyAccess {
333 #[serde(rename = "read")]
334 Read,
335 #[serde(rename = "write")]
336 Write,
337 #[serde(rename = "readwrite")]
338 ReadWrite,
339}
340
341impl PropertyAccess {
342 pub fn read(&self) -> bool {
343 matches!(self, PropertyAccess::Read | PropertyAccess::ReadWrite)
344 }
345
346 pub fn write(&self) -> bool {
347 matches!(self, PropertyAccess::Write | PropertyAccess::ReadWrite)
348 }
349
350 fn xml_value(&self) -> &'static str {
351 match self {
352 PropertyAccess::Read => "read",
353 PropertyAccess::Write => "write",
354 PropertyAccess::ReadWrite => "readwrite",
355 }
356 }
357}
358
359#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
361pub struct Property<'a> {
362 #[serde(rename = "@name", borrow)]
363 name: PropertyName<'a>,
364
365 #[serde(rename = "@type")]
366 ty: Signature,
367 #[serde(rename = "@access")]
368 access: PropertyAccess,
369
370 #[serde(rename = "annotation", default)]
371 annotations: Vec<Annotation>,
372 #[serde(skip)]
373 docstring: Option<String>,
374 #[serde(skip)]
375 tp_type: Option<String>,
376}
377
378impl Property<'_> {
379 pub fn name(&self) -> PropertyName<'_> {
381 self.name.as_ref()
382 }
383
384 pub fn ty(&self) -> &Signature {
386 &self.ty
387 }
388
389 pub fn access(&self) -> PropertyAccess {
391 self.access
392 }
393
394 pub fn annotations(&self) -> &[Annotation] {
396 &self.annotations
397 }
398
399 pub fn docstring(&self) -> Option<&str> {
405 self.docstring.as_deref()
406 }
407
408 pub fn tp_type(&self) -> Option<&str> {
413 self.tp_type.as_deref()
414 }
415
416 fn write_xml<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
417 write!(
418 w,
419 "<property name=\"{}\" type=\"{}\" access=\"{}\"",
420 escape(self.name.as_str()),
421 escape(&self.ty.to_string()),
422 self.access.xml_value()
423 )?;
424 if self.annotations.is_empty() {
425 return write!(w, "/>");
426 }
427 write!(w, ">")?;
428 for annotation in &self.annotations {
429 annotation.write_xml(w)?;
430 }
431 write!(w, "</property>")
432 }
433}
434
435#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
437pub struct Interface<'a> {
438 #[serde(rename = "@name", borrow)]
439 name: InterfaceName<'a>,
440
441 #[serde(rename = "method", default)]
442 methods: Vec<Method<'a>>,
443 #[serde(rename = "property", default)]
444 properties: Vec<Property<'a>>,
445 #[serde(rename = "signal", default)]
446 signals: Vec<Signal<'a>>,
447 #[serde(rename = "annotation", default)]
448 annotations: Vec<Annotation>,
449 #[serde(skip)]
450 docstring: Option<String>,
451 #[serde(skip)]
452 telepathy_types: Vec<telepathy::TypeDef>,
453}
454
455impl<'a> Interface<'a> {
456 pub fn name(&self) -> InterfaceName<'_> {
458 self.name.as_ref()
459 }
460
461 pub fn methods(&self) -> &[Method<'a>] {
463 &self.methods
464 }
465
466 pub fn signals(&self) -> &[Signal<'a>] {
468 &self.signals
469 }
470
471 pub fn properties(&self) -> &[Property<'_>] {
473 &self.properties
474 }
475
476 pub fn annotations(&self) -> &[Annotation] {
478 &self.annotations
479 }
480
481 pub fn docstring(&self) -> Option<&str> {
487 self.docstring.as_deref()
488 }
489
490 pub fn telepathy_types(&self) -> &[telepathy::TypeDef] {
492 &self.telepathy_types
493 }
494
495 fn write_xml<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
496 write!(w, "<interface name=\"{}\"", escape(self.name.as_str()))?;
497 if self.methods.is_empty()
498 && self.properties.is_empty()
499 && self.signals.is_empty()
500 && self.annotations.is_empty()
501 {
502 return write!(w, "/>");
503 }
504 write!(w, ">")?;
505 for method in &self.methods {
506 method.write_xml(w)?;
507 }
508 for property in &self.properties {
509 property.write_xml(w)?;
510 }
511 for signal in &self.signals {
512 signal.write_xml(w)?;
513 }
514 for annotation in &self.annotations {
515 annotation.write_xml(w)?;
516 }
517 write!(w, "</interface>")
518 }
519}
520
521#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
523pub struct Node<'a> {
524 #[serde(rename = "@name")]
525 name: Option<String>,
526
527 #[serde(rename = "interface", default, borrow)]
528 interfaces: Vec<Interface<'a>>,
529 #[serde(rename = "node", default, borrow)]
530 nodes: Vec<Node<'a>>,
531 #[serde(skip)]
532 docstring: Option<String>,
533 #[serde(skip)]
534 telepathy_types: Vec<telepathy::TypeDef>,
535}
536
537impl<'a> Node<'a> {
538 pub fn from_reader<R: Read>(reader: R) -> Result<Node<'a>> {
543 Ok(Node::from_reader_with_warnings(reader)?.0)
544 }
545
546 pub fn from_reader_with_warnings<R: Read>(mut reader: R) -> Result<(Node<'a>, Vec<Warning>)> {
558 let mut input = String::new();
559 reader.read_to_string(&mut input)?;
560
561 xml::parse_with_warnings(&input)
562 }
563
564 pub fn to_writer<W: Write>(&self, writer: W) -> Result<()> {
570 let mut writer = BufWriter::new(writer);
571 self.write_xml(&mut writer)?;
572 writer.flush()?;
573
574 Ok(())
575 }
576
577 pub fn name(&self) -> Option<&str> {
579 self.name.as_deref()
580 }
581
582 pub fn nodes(&self) -> &[Node<'a>] {
584 &self.nodes
585 }
586
587 pub fn interfaces(&self) -> &[Interface<'a>] {
589 &self.interfaces
590 }
591
592 pub fn docstring(&self) -> Option<&str> {
598 self.docstring.as_deref()
599 }
600
601 pub fn telepathy_types(&self) -> &[telepathy::TypeDef] {
603 &self.telepathy_types
604 }
605
606 fn write_xml<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
607 write!(w, "<node")?;
608 if let Some(name) = &self.name {
609 write!(w, " name=\"{}\"", escape(name))?;
610 }
611 if self.interfaces.is_empty() && self.nodes.is_empty() {
612 return write!(w, "/>");
613 }
614 write!(w, ">")?;
615 for interface in &self.interfaces {
616 interface.write_xml(w)?;
617 }
618 for node in &self.nodes {
619 node.write_xml(w)?;
620 }
621 write!(w, "</node>")
622 }
623}
624
625impl<'a> TryFrom<&'a str> for Node<'a> {
626 type Error = Error;
627
628 fn try_from(s: &'a str) -> Result<Node<'a>> {
630 xml::parse(s)
631 }
632}
633
634#[derive(Debug, Serialize, Clone, PartialEq)]
639pub struct Signature(zvariant::Signature);
640
641impl Signature {
642 pub fn inner(&self) -> &zvariant::Signature {
644 &self.0
645 }
646
647 pub fn into_inner(self) -> zvariant::Signature {
649 self.0
650 }
651}
652
653impl<'de> serde::de::Deserialize<'de> for Signature {
654 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
655 where
656 D: serde::de::Deserializer<'de>,
657 {
658 String::deserialize(deserializer).and_then(|s| {
659 zvariant::Signature::try_from(s.as_bytes())
660 .map_err(serde::de::Error::custom)
661 .map(Signature)
662 })
663 }
664}
665
666impl Deref for Signature {
667 type Target = zvariant::Signature;
668
669 fn deref(&self) -> &Self::Target {
670 self.inner()
671 }
672}
673
674impl PartialEq<str> for Signature {
675 fn eq(&self, other: &str) -> bool {
676 self.0 == other
677 }
678}