Skip to content

Commit

Permalink
Merge pull request #449 from mercedes-benz/split-xml-mod-into-crate
Browse files Browse the repository at this point in the history
🚚 Move xml mod into a separate crate, zbus_xml
  • Loading branch information
zeenix authored Aug 18, 2023
2 parents 5098236 + b93560b commit 4169a3f
Show file tree
Hide file tree
Showing 17 changed files with 169 additions and 99 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
"zvariant_derive",
"zvariant_utils",
"zbus_macros",
"zbus_xml",
"zbus_xmlgen",
]
resolver = "2"
6 changes: 1 addition & 5 deletions zbus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ async-io = [
tokio = ["dep:tokio"]
vsock = ["dep:vsock", "dep:async-io"]
tokio-vsock = ["dep:tokio-vsock", "tokio"]
xml = ["dep:quick-xml"]

[dependencies]
byteorder = "1.4.3"
Expand Down Expand Up @@ -80,10 +79,6 @@ tokio = { version = "1.21.2", optional = true, features = [
tracing = "0.1.37"
vsock = { version = "0.3.0", optional = true }
tokio-vsock = { version = "0.3.3", optional = true }
quick-xml = { version = "0.27.1", features = [
"serialize",
"overlapped-lists",
], optional = true }
xdg-home = "1.0.0"

[target.'cfg(windows)'.dependencies]
Expand Down Expand Up @@ -117,6 +112,7 @@ async-process = "1.7.0"
async-recursion = "1.0.0"

[dev-dependencies]
zbus_xml = { path = "../zbus_xml", version = "4.0.0" }
doc-comment = "0.3.3"
futures-util = "0.3.25" # activate default features
ntest = "0.9.0"
Expand Down
20 changes: 0 additions & 20 deletions zbus/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#[cfg(feature = "xml")]
use quick_xml::de::DeError;
use static_assertions::assert_impl_all;
use std::{convert::Infallible, error, fmt, io, sync::Arc};
use zbus_names::{Error as NamesError, OwnedErrorName};
Expand Down Expand Up @@ -49,9 +47,6 @@ pub enum Error {
Unsupported,
/// A [`fdo::Error`] transformed into [`Error`].
FDO(Box<fdo::Error>),
#[cfg(feature = "xml")]
/// An XML error from quick_xml
QuickXml(DeError),
/// The requested name was already claimed by another peer.
NameTaken,
/// Invalid [match rule][MR] string.
Expand Down Expand Up @@ -89,8 +84,6 @@ impl PartialEq for Error {
(Self::Names(s), Self::Names(o)) => s == o,
(Self::NameTaken, Self::NameTaken) => true,
(Error::InputOutput(_), Self::InputOutput(_)) => false,
#[cfg(feature = "xml")]
(Self::QuickXml(_), Self::QuickXml(_)) => false,
(Self::Failure(s1), Self::Failure(s2)) => s1 == s2,
(_, _) => false,
}
Expand All @@ -113,8 +106,6 @@ impl error::Error for Error {
Error::InvalidGUID => None,
Error::Unsupported => None,
Error::FDO(e) => Some(e),
#[cfg(feature = "xml")]
Error::QuickXml(e) => Some(e),
Error::InvalidField => None,
Error::MissingField => None,
Error::NameTaken => None,
Expand Down Expand Up @@ -149,8 +140,6 @@ impl fmt::Display for Error {
Error::InvalidGUID => write!(f, "Invalid GUID"),
Error::Unsupported => write!(f, "Connection support is lacking"),
Error::FDO(e) => write!(f, "{e}"),
#[cfg(feature = "xml")]
Error::QuickXml(e) => write!(f, "XML error: {e}"),
Error::NameTaken => write!(f, "name already taken on the bus"),
Error::InvalidMatchRule => write!(f, "Invalid match rule string"),
Error::Failure(e) => write!(f, "{e}"),
Expand Down Expand Up @@ -182,8 +171,6 @@ impl Clone for Error {
Error::InvalidGUID => Error::InvalidGUID,
Error::Unsupported => Error::Unsupported,
Error::FDO(e) => Error::FDO(e.clone()),
#[cfg(feature = "xml")]
Error::QuickXml(e) => Error::QuickXml(e.clone()),
Error::NameTaken => Error::NameTaken,
Error::InvalidMatchRule => Error::InvalidMatchRule,
Error::Failure(e) => Error::Failure(e.clone()),
Expand Down Expand Up @@ -230,13 +217,6 @@ impl From<fdo::Error> for Error {
}
}

#[cfg(feature = "xml")]
impl From<DeError> for Error {
fn from(val: DeError) -> Self {
Error::QuickXml(val)
}
}

impl From<Infallible> for Error {
fn from(i: Infallible) -> Self {
match i {}
Expand Down
3 changes: 0 additions & 3 deletions zbus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,6 @@ pub use connection::Socket;

pub mod blocking;

#[cfg(feature = "xml")]
pub mod xml;

pub use zbus_macros::{dbus_interface, dbus_proxy, DBusError};

// Required for the macros to function within this crate.
Expand Down
62 changes: 29 additions & 33 deletions zbus/tests/e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use zbus::{
fdo::{ObjectManager, ObjectManagerProxy},
message::{self, Builder},
object_server::ResponseDispatchNotifier,
DBusError, MessageStream,
DBusError, Error, MessageStream,
};
use zvariant::{DeserializeDict, Optional, OwnedValue, SerializeDict, Str, Type, Value};

Expand Down Expand Up @@ -529,39 +529,35 @@ async fn my_iface_test(conn: Connection, event: Event) -> zbus::Result<u32> {

assert_eq!(proxy.optional_property().await?, Some(42).into());

#[cfg(feature = "xml")]
{
let xml = proxy.introspect().await?;
debug!("Introspection: {}", xml);
#[cfg(feature = "xml")]
let node = zbus::xml::Node::from_reader(xml.as_bytes())?;
let ifaces = node.interfaces();
let iface = ifaces
let xml = proxy.introspect().await?;
debug!("Introspection: {}", xml);
let node =
zbus_xml::Node::from_reader(xml.as_bytes()).map_err(|e| Error::Failure(e.to_string()))?;
let ifaces = node.interfaces();
let iface = ifaces
.iter()
.find(|i| i.name() == "org.freedesktop.MyIface")
.unwrap();
let methods = iface.methods();
for method in methods {
if method.name() != "TestSingleStructRet" && method.name() != "TestMultiRet" {
continue;
}
let args = method.args();
let mut out_args = args
.iter()
.find(|i| i.name() == "org.freedesktop.MyIface")
.unwrap();
let methods = iface.methods();
for method in methods {
if method.name() != "TestSingleStructRet" && method.name() != "TestMultiRet" {
continue;
}
let args = method.args();
#[cfg(feature = "xml")]
let mut out_args = args
.iter()
.filter(|a| a.direction().unwrap() == zbus::xml::ArgDirection::Out);

if method.name() == "TestSingleStructRet" {
assert_eq!(args.len(), 1);
assert_eq!(out_args.next().unwrap().ty().signature(), "(is)");
assert!(out_args.next().is_none());
} else {
assert_eq!(args.len(), 2);
let foo = out_args.find(|a| a.name() == Some("foo")).unwrap();
assert_eq!(foo.ty().signature(), "i");
let bar = out_args.find(|a| a.name() == Some("bar")).unwrap();
assert_eq!(bar.ty().signature(), "s");
}
.filter(|a| a.direction().unwrap() == zbus_xml::ArgDirection::Out);

if method.name() == "TestSingleStructRet" {
assert_eq!(args.len(), 1);
assert_eq!(out_args.next().unwrap().ty().signature(), "(is)");
assert!(out_args.next().is_none());
} else {
assert_eq!(args.len(), 2);
let foo = out_args.find(|a| a.name() == Some("foo")).unwrap();
assert_eq!(foo.ty().signature(), "i");
let bar = out_args.find(|a| a.name() == Some("bar")).unwrap();
assert_eq!(bar.ty().signature(), "s");
}
}
// build-time check to see if macro is doing the right thing.
Expand Down
1 change: 0 additions & 1 deletion zbus_names/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use zvariant::Error as VariantError;
///
/// The various errors that can be reported by this crate.
#[derive(Clone, Debug)]
#[allow(clippy::upper_case_acronyms)]
#[non_exhaustive]
pub enum Error {
Variant(VariantError),
Expand Down
27 changes: 27 additions & 0 deletions zbus_xml/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "zbus_xml"
version = "4.0.0"
authors = ["Zeeshan Ali Khan <[email protected]>"]
edition = "2021"
rust-version = "1.64"

description = "API to handle D-Bus introspection XML"
repository = "https://github.com/dbus2/zbus/"
keywords = ["D-Bus", "DBus", "IPC", "XML"]
license = "MIT"
categories = ["parsing"]
readme = "README.md"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
zvariant = { path = "../zvariant", version = "4.0.0", default-features = false }
zbus_names = { path = "../zbus_names", version = "3.0" }
quick-xml = { version = "0.27.1", features = ["serialize", "overlapped-lists"] }
static_assertions = "1.1.0"

[dev-dependencies]
doc-comment = "0.3.3"

[package.metadata.docs.rs]
all-features = true
targets = ["x86_64-unknown-linux-gnu"]
17 changes: 17 additions & 0 deletions zbus_xml/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# 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
66 changes: 66 additions & 0 deletions zbus_xml/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use quick_xml::de::DeError;
use static_assertions::assert_impl_all;
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),
}

assert_impl_all!(Error: Send, Sync, Unpin);

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,
(_, _) => 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),
}
}
}

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}"),
}
}
}

impl From<VariantError> for Error {
fn from(val: VariantError) -> Self {
Error::Variant(val)
}
}

impl From<DeError> for Error {
fn from(val: DeError) -> Self {
Error::QuickXml(val)
}
}

impl From<Infallible> for Error {
fn from(i: Infallible) -> Self {
match i {}
}
}

/// Alias for a `Result` with the error type `zbus_xml::Error`.
pub type Result<T> = std::result::Result<T, Error>;
45 changes: 20 additions & 25 deletions zbus/src/xml.rs β†’ zbus_xml/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
//! Introspection XML support (`xml` feature)
//!
//! Thanks to the [`org.freedesktop.DBus.Introspectable`] interface, objects may be introspected at
//! runtime, returning an XML string that describes the object.
//!
//! This optional `xml` module 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()`].
//!
//! * [Introspection format] in the DBus specification
//!
//! [`Node.from_reader()`]: 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
#![deny(rust_2018_idioms)]
#![doc(
html_logo_url = "https://storage.googleapis.com/fdo-gitlab-uploads/project/avatar/3213/zbus-logomark.png"
)]
#![doc = include_str!("../README.md")]
#![doc(test(attr(
warn(unused),
deny(warnings),
// 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 static_assertions::assert_impl_all;
use std::{
io::{BufReader, Read, Write},
result::Result,
};
use std::io::{BufReader, Read, Write};

use crate::{
names::{InterfaceName, MemberName},
zvariant::CompleteType,
Error,
};
use zbus_names::{InterfaceName, MemberName};
use zvariant::CompleteType;

/// Annotations are generic key/value pairs of metadata.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
Expand Down Expand Up @@ -277,14 +272,14 @@ assert_impl_all!(Node<'_>: Send, Sync, Unpin);

impl<'a> Node<'a> {
/// Parse the introspection XML document from reader.
pub fn from_reader<R: Read>(reader: R) -> Result<Node<'a>, Error> {
pub fn from_reader<R: Read>(reader: R) -> Result<Node<'a>> {
let mut deserializer = Deserializer::from_reader(BufReader::new(reader));
deserializer.event_buffer_size(Some(1024_usize.try_into().unwrap()));
Ok(Node::deserialize(&mut deserializer)?)
}

/// Write the XML document to writer.
pub fn to_writer<W: Write>(&self, writer: W) -> Result<(), Error> {
pub fn to_writer<W: Write>(&self, writer: W) -> Result<()> {
// Need this wrapper until this is resolved: https://github.com/tafia/quick-xml/issues/499
struct Writer<T>(T);

Expand Down Expand Up @@ -322,7 +317,7 @@ 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<Node<'a>, Error> {
fn try_from(s: &'a str) -> Result<Node<'a>> {
let mut deserializer = Deserializer::from_str(s);
deserializer.event_buffer_size(Some(1024_usize.try_into().unwrap()));
Ok(Node::deserialize(&mut deserializer)?)
Expand Down
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 4169a3f

Please sign in to comment.