zbus_xml-5.1.0/.cargo_vcs_info.json0000644000000001460000000000100127030ustar { "git": { "sha1": "9b7f5fadddf3375aa23d5953388b19df7293b1ed" }, "path_in_vcs": "zbus_xml" }zbus_xml-5.1.0/CHANGELOG.md000064400000000000000000000005601046102023000133040ustar 00000000000000# zbus_xml Changelog ## 5.1.0 - 2026-01-09 ### Changed - 🚚 Update name of Github space from dbus2 to z-galaxy. ### Dependencies - ⬆️ Update quick-xml to 0.38. ### Fixed - 🩹 Don't use workspace for local deps. - 🐛 Raise XML parsing buffer size. ### Other - 🧑‍💻 Use workspace dependencies. ### Removed - ➖ Drop `static_assertions` dep. zbus_xml-5.1.0/Cargo.lock0000644000000137630000000000100106670ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "doc-comment" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" [[package]] name = "endi" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" [[package]] name = "enumflags2" version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" dependencies = [ "enumflags2_derive", "serde", ] [[package]] name = "enumflags2_derive" version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "indexmap" version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "proc-macro-crate" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" dependencies = [ "unicode-ident", ] [[package]] name = "quick-xml" version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" dependencies = [ "memchr", "serde", ] [[package]] name = "quote" version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" dependencies = [ "proc-macro2", ] [[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", ] [[package]] name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "syn" version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "toml_datetime" version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ "indexmap", "toml_datetime", "toml_parser", "winnow", ] [[package]] name = "toml_parser" version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" dependencies = [ "winnow", ] [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "winnow" version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] [[package]] name = "zbus_names" version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afef568512468eb4a660f033092d38fe2508eea7517ad59c7b2b871d231d7deb" dependencies = [ "serde", "winnow", "zvariant", ] [[package]] name = "zbus_xml" version = "5.1.0" dependencies = [ "doc-comment", "quick-xml", "serde", "zbus_names", "zvariant", ] [[package]] name = "zvariant" version = "5.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "788ca131e3757991e4b9fe9f7b78ae302749ed96093ff60858a1f4732b04b164" dependencies = [ "endi", "enumflags2", "serde", "winnow", "zvariant_derive", "zvariant_utils", ] [[package]] name = "zvariant_derive" version = "5.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e69a2f6b221a6fec9bd6bcc77c19360cca106f92a5fd948b8aa17d2339c7505" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", "syn", "zvariant_utils", ] [[package]] name = "zvariant_utils" version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9" dependencies = [ "proc-macro2", "quote", "serde", "syn", "winnow", ] zbus_xml-5.1.0/Cargo.toml0000644000000027710000000000100107070ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2024" rust-version = "1.85" name = "zbus_xml" version = "5.1.0" authors = ["Zeeshan Ali Khan "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "API to handle D-Bus introspection XML" readme = "README.md" keywords = [ "D-Bus", "DBus", "IPC", "XML", ] categories = ["parsing"] license = "MIT" repository = "https://github.com/z-galaxy/zbus/" resolver = "2" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] [lib] name = "zbus_xml" path = "src/lib.rs" [[test]] name = "tests" path = "tests/tests.rs" [dependencies.quick-xml] version = "0.38" features = [ "serialize", "overlapped-lists", ] [dependencies.serde] version = "1.0.200" features = ["derive"] [dependencies.zbus_names] version = "4.3.0" [dependencies.zvariant] version = "5.9.0" [dev-dependencies.doc-comment] version = "0.3.3" [lints.rust.unexpected_cfgs] level = "warn" priority = 0 check-cfg = ["cfg(tokio_unstable)"] zbus_xml-5.1.0/Cargo.toml.orig000064400000000000000000000013151046102023000143610ustar 00000000000000[package] name = "zbus_xml" version = "5.1.0" authors = ["Zeeshan Ali Khan "] edition = { workspace = true } rust-version = { workspace = true } description = "API to handle D-Bus introspection XML" repository = { workspace = true } keywords = ["D-Bus", "DBus", "IPC", "XML"] license = { workspace = true } categories = ["parsing"] readme = "README.md" [dependencies] serde.workspace = true zvariant = { path = "../zvariant", version = "5.9.0" } zbus_names = { path = "../zbus_names", version = "4.3.0" } quick-xml.workspace = true [dev-dependencies] doc-comment.workspace = true [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] [lints] workspace = true zbus_xml-5.1.0/LICENSE000064400000000000000000000020701046102023000124760ustar 00000000000000Copyright (c) 2024 Zeeshan Ali Khan & zbus contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. zbus_xml-5.1.0/README.md000064400000000000000000000015551046102023000127570ustar 00000000000000# zbus_xml [![](https://docs.rs/zbus_xml/badge.svg)](https://docs.rs/zbus_xml/) [![](https://img.shields.io/crates/v/zbus_xml)](https://crates.io/crates/zbus_xml) API to handle D-Bus introspection XML. Thanks to the [`org.freedesktop.DBus.Introspectable`] interface, objects may be introspected at runtime, returning an XML string that describes the object. This crate provides facilities to parse the XML data into more convenient Rust structures. The XML string may be parsed to a tree with [`Node::from_reader`]. **Status:** Stable. [`Node::from_reader`]: https://docs.rs/zbus_xml/latest/zbus_xml/struct.Node.html#method.from_reader [Introspection format]: https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format [`org.freedesktop.DBus.Introspectable`]: https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable zbus_xml-5.1.0/src/error.rs000064400000000000000000000035751046102023000137720ustar 00000000000000use quick_xml::{de::DeError, se::SeError}; use std::{convert::Infallible, error, fmt}; use zvariant::Error as VariantError; /// The error type for `zbus_names`. /// /// The various errors that can be reported by this crate. #[derive(Clone, Debug)] #[non_exhaustive] pub enum Error { Variant(VariantError), /// An XML error from quick_xml QuickXml(DeError), /// An XML serialization error from quick_xml QuickXmlSer(SeError), } impl PartialEq for Error { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Variant(s), Self::Variant(o)) => s == o, (Self::QuickXml(_), Self::QuickXml(_)) => false, (Self::QuickXmlSer(_), Self::QuickXmlSer(_)) => false, (_, _) => false, } } } impl error::Error for Error { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match self { Error::Variant(e) => Some(e), Error::QuickXml(e) => Some(e), Error::QuickXmlSer(e) => Some(e), } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::Variant(e) => write!(f, "{e}"), Error::QuickXml(e) => write!(f, "XML error: {e}"), Error::QuickXmlSer(e) => write!(f, "XML serialization error: {e}"), } } } impl From for Error { fn from(val: VariantError) -> Self { Error::Variant(val) } } impl From for Error { fn from(val: DeError) -> Self { Error::QuickXml(val) } } impl From for Error { fn from(val: SeError) -> Self { Error::QuickXmlSer(val) } } impl From for Error { fn from(i: Infallible) -> Self { match i {} } } /// Alias for a `Result` with the error type `zbus_xml::Error`. pub type Result = std::result::Result; zbus_xml-5.1.0/src/lib.rs000064400000000000000000000217151046102023000134030ustar 00000000000000#![deny(rust_2018_idioms)] #![doc( html_logo_url = "https://raw.githubusercontent.com/z-galaxy/zbus/9f7a90d2b594ddc48b7a5f39fda5e00cd56a7dfb/logo.png" )] #![doc = include_str!("../README.md")] #![doc(test(attr( warn(unused), deny(warnings), allow(dead_code), // W/o this, we seem to get some bogus warning about `extern crate zbus`. allow(unused_extern_crates), )))] mod error; pub use error::{Error, Result}; use quick_xml::{de::Deserializer, se::to_writer}; use serde::{Deserialize, Serialize}; use std::{ io::{BufReader, Read, Write}, ops::Deref, }; use zbus_names::{InterfaceName, MemberName, PropertyName}; /// Annotations are generic key/value pairs of metadata. #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] pub struct Annotation { #[serde(rename = "@name")] name: String, #[serde(rename = "@value")] value: String, } impl Annotation { /// Return the annotation name/key. pub fn name(&self) -> &str { &self.name } /// Return the annotation value. pub fn value(&self) -> &str { &self.value } } /// A direction of an argument #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum ArgDirection { #[serde(rename = "in")] In, #[serde(rename = "out")] Out, } /// An argument #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct Arg { #[serde(rename = "@name")] name: Option, #[serde(rename = "@type")] ty: Signature, #[serde(rename = "@direction")] direction: Option, #[serde(rename = "annotation", default)] annotations: Vec, } impl Arg { /// Return the argument name, if any. pub fn name(&self) -> Option<&str> { self.name.as_deref() } /// Return the argument type. pub fn ty(&self) -> &Signature { &self.ty } /// Return the argument direction, if any. pub fn direction(&self) -> Option { self.direction } /// Return the associated annotations. pub fn annotations(&self) -> &[Annotation] { &self.annotations } } /// A method #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct Method<'a> { #[serde(rename = "@name", borrow)] name: MemberName<'a>, #[serde(rename = "arg", default)] args: Vec, #[serde(rename = "annotation", default)] annotations: Vec, } impl Method<'_> { /// Return the method name. pub fn name(&self) -> MemberName<'_> { self.name.as_ref() } /// Return the method arguments. pub fn args(&self) -> &[Arg] { &self.args } /// Return the method annotations. pub fn annotations(&self) -> &[Annotation] { &self.annotations } } /// A signal #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct Signal<'a> { #[serde(rename = "@name", borrow)] name: MemberName<'a>, #[serde(rename = "arg", default)] args: Vec, #[serde(rename = "annotation", default)] annotations: Vec, } impl Signal<'_> { /// Return the signal name. pub fn name(&self) -> MemberName<'_> { self.name.as_ref() } /// Return the signal arguments. pub fn args(&self) -> &[Arg] { &self.args } /// Return the signal annotations. pub fn annotations(&self) -> &[Annotation] { &self.annotations } } /// The possible property access types #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum PropertyAccess { #[serde(rename = "read")] Read, #[serde(rename = "write")] Write, #[serde(rename = "readwrite")] ReadWrite, } impl PropertyAccess { pub fn read(&self) -> bool { matches!(self, PropertyAccess::Read | PropertyAccess::ReadWrite) } pub fn write(&self) -> bool { matches!(self, PropertyAccess::Write | PropertyAccess::ReadWrite) } } /// A property #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct Property<'a> { #[serde(rename = "@name", borrow)] name: PropertyName<'a>, #[serde(rename = "@type")] ty: Signature, #[serde(rename = "@access")] access: PropertyAccess, #[serde(rename = "annotation", default)] annotations: Vec, } impl Property<'_> { /// Returns the property name. pub fn name(&self) -> PropertyName<'_> { self.name.as_ref() } /// Returns the property type. pub fn ty(&self) -> &Signature { &self.ty } /// Returns the property access flags (should be "read", "write" or "readwrite"). pub fn access(&self) -> PropertyAccess { self.access } /// Return the associated annotations. pub fn annotations(&self) -> &[Annotation] { &self.annotations } } /// An interface #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct Interface<'a> { #[serde(rename = "@name", borrow)] name: InterfaceName<'a>, #[serde(rename = "method", default)] methods: Vec>, #[serde(rename = "property", default)] properties: Vec>, #[serde(rename = "signal", default)] signals: Vec>, #[serde(rename = "annotation", default)] annotations: Vec, } impl<'a> Interface<'a> { /// Returns the interface name. pub fn name(&self) -> InterfaceName<'_> { self.name.as_ref() } /// Returns the interface methods. pub fn methods(&self) -> &[Method<'a>] { &self.methods } /// Returns the interface signals. pub fn signals(&self) -> &[Signal<'a>] { &self.signals } /// Returns the interface properties. pub fn properties(&self) -> &[Property<'_>] { &self.properties } /// Return the associated annotations. pub fn annotations(&self) -> &[Annotation] { &self.annotations } } /// An introspection tree node (typically the root of the XML document). #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct Node<'a> { #[serde(rename = "@name")] name: Option, #[serde(rename = "interface", default, borrow)] interfaces: Vec>, #[serde(rename = "node", default, borrow)] nodes: Vec>, } impl<'a> Node<'a> { /// Parse the introspection XML document from reader. pub fn from_reader(reader: R) -> Result> { let mut deserializer = Deserializer::from_reader(BufReader::new(reader)); deserializer.event_buffer_size(Some(4096_usize.try_into().unwrap())); Ok(Node::deserialize(&mut deserializer)?) } /// Write the XML document to writer. pub fn to_writer(&self, writer: W) -> Result<()> { // Need this wrapper until this is resolved: https://github.com/tafia/quick-xml/issues/499 struct Writer(T); impl std::fmt::Write for Writer where T: Write, { fn write_str(&mut self, s: &str) -> std::fmt::Result { self.0.write_all(s.as_bytes()).map_err(|_| std::fmt::Error) } } to_writer(Writer(writer), &self)?; Ok(()) } /// Returns the node name, if any. pub fn name(&self) -> Option<&str> { self.name.as_deref() } /// Returns the children nodes. pub fn nodes(&self) -> &[Node<'a>] { &self.nodes } /// Returns the interfaces on this node. pub fn interfaces(&self) -> &[Interface<'a>] { &self.interfaces } } impl<'a> TryFrom<&'a str> for Node<'a> { type Error = Error; /// Parse the introspection XML document from `s`. fn try_from(s: &'a str) -> Result> { let mut deserializer = Deserializer::from_str(s); deserializer.event_buffer_size(Some(4096_usize.try_into().unwrap())); Ok(Node::deserialize(&mut deserializer)?) } } /// A thin wrapper around `zvariant::parsed::Signature`. /// /// This is to allow `Signature` to be deserialized from an owned string, which is what quick-xml2 /// deserializer does. #[derive(Debug, Serialize, Clone, PartialEq)] pub struct Signature(zvariant::Signature); impl Signature { /// Return the inner `zvariant::Signature`. pub fn inner(&self) -> &zvariant::Signature { &self.0 } /// Convert this `Signature` into the inner `zvariant::parsed::Signature`. pub fn into_inner(self) -> zvariant::Signature { self.0 } } impl<'de> serde::de::Deserialize<'de> for Signature { fn deserialize(deserializer: D) -> std::result::Result where D: serde::de::Deserializer<'de>, { String::deserialize(deserializer).and_then(|s| { zvariant::Signature::try_from(s.as_bytes()) .map_err(serde::de::Error::custom) .map(Signature) }) } } impl Deref for Signature { type Target = zvariant::Signature; fn deref(&self) -> &Self::Target { self.inner() } } impl PartialEq for Signature { fn eq(&self, other: &str) -> bool { self.0 == other } } zbus_xml-5.1.0/tests/data/invalid_arg_type.xml000064400000000000000000000005751046102023000176160ustar 00000000000000 zbus_xml-5.1.0/tests/data/sample_object0.xml000064400000000000000000000022631046102023000171610ustar 00000000000000 zbus_xml-5.1.0/tests/tests.rs000064400000000000000000000020611046102023000143430ustar 00000000000000use quick_xml::de::DeError; use std::error::Error; use zbus_xml::{ArgDirection, Node}; #[test] fn serde() -> Result<(), Box> { let example = include_str!("data/sample_object0.xml"); let node_r = Node::from_reader(example.as_bytes())?; let node = Node::try_from(example)?; assert_eq!(node, node_r); assert_eq!(node.interfaces().len(), 1); assert_eq!(node.interfaces()[0].methods().len(), 3); assert_eq!( node.interfaces()[0].methods()[0].args()[0] .direction() .unwrap(), ArgDirection::In ); assert_eq!(node.nodes().len(), 4); let node_str: Node<'_> = example.try_into()?; assert_eq!(node_str.interfaces().len(), 1); assert_eq!(node_str.nodes().len(), 4); let mut writer = Vec::with_capacity(128); node.to_writer(&mut writer).unwrap(); Ok(()) } #[test] fn invalid_arg_type() { let input = include_str!("data/invalid_arg_type.xml"); assert!(matches!( Node::try_from(input), Err(zbus_xml::Error::QuickXml(DeError::Custom(_))) )); }