#![doc(html_root_url = "https://docs.rs/zbus-lockstep/0.3.0")]
#![allow(clippy::missing_errors_doc)]
mod macros;
mod utils;
use std::io::Read;
pub use macros::resolve_xml_path;
pub use utils::signatures_are_eq;
use zbus::{
xml::{Arg, Node},
zvariant::Signature,
Error::{InterfaceNotFound, MissingParameter},
};
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
#[derive(Debug, PartialEq, Eq)]
pub enum MsgType {
Method,
Signal,
Property,
}
pub fn get_signal_body_type<'a>(
mut xml: impl Read,
interface_name: &str,
member_name: &str,
arg: Option<&str>,
) -> Result<Signature<'a>> {
let node = Node::from_reader(&mut xml)?;
let interfaces = node.interfaces();
let interface = interfaces
.iter()
.find(|iface| iface.name() == interface_name)
.ok_or(InterfaceNotFound)?;
let singals = interface.signals();
let signal = singals
.iter()
.find(|signal| signal.name() == member_name)
.ok_or(MissingParameter("no signal matching supplied member"))?;
let signature = {
if let Some(arg_name) = arg {
let args = signal.args();
let arg = args
.iter()
.find(|arg| arg.name() == Some(arg_name))
.ok_or(MissingParameter("no matching argument found"))?;
arg.ty().to_owned()
} else {
signal.args().into_iter().map(Arg::ty).collect::<String>()
}
};
Ok(Signature::from_string_unchecked(signature))
}
pub fn get_property_type<'a>(
mut xml: impl Read,
interface_name: &str,
property_name: &str,
) -> Result<Signature<'a>> {
let node = Node::from_reader(&mut xml)?;
let interfaces = node.interfaces();
let interface = interfaces
.iter()
.find(|iface| iface.name() == interface_name)
.ok_or(InterfaceNotFound)?;
let properties = interface.properties();
let property = properties
.iter()
.find(|property| property.name() == property_name)
.ok_or(MissingParameter("no property matching supplied member"))?;
let signature = property.ty().to_owned();
Ok(Signature::from_string_unchecked(signature))
}
pub fn get_method_return_type<'a>(
mut xml: impl Read,
interface_name: &str,
member_name: &str,
arg_name: Option<&str>,
) -> Result<Signature<'a>> {
let node = Node::from_reader(&mut xml)?;
let interfaces = node.interfaces();
let interface = interfaces
.iter()
.find(|iface| iface.name() == interface_name)
.ok_or(InterfaceNotFound)?;
let methods = interface.methods();
let method = methods
.iter()
.find(|method| method.name() == member_name)
.ok_or(MissingParameter("no method matches supplied member"))?;
let args = method.args();
let signature = if arg_name.is_some() {
args.iter()
.find(|arg| arg.name() == arg_name)
.ok_or(MissingParameter("no matching argument found"))?
.ty()
.to_owned()
} else {
args.iter()
.filter(|arg| arg.direction() == Some("out"))
.map(|arg| arg.ty())
.collect::<String>()
};
Ok(Signature::from_string_unchecked(signature))
}
pub fn get_method_args_type<'a>(
mut xml: impl Read,
interface_name: &str,
member_name: &str,
arg_name: Option<&str>,
) -> Result<Signature<'a>> {
let node = Node::from_reader(&mut xml)?;
let interfaces = node.interfaces();
let interface = interfaces
.iter()
.find(|iface| iface.name() == interface_name)
.ok_or(InterfaceNotFound)?;
let methods = interface.methods();
let method = methods
.iter()
.find(|method| method.name() == member_name)
.ok_or(MissingParameter("no method matches supplied member"))?;
let args = method.args();
let signature = if arg_name.is_some() {
args.iter()
.find(|arg| arg.name() == arg_name)
.ok_or(MissingParameter("no matching argument found"))?
.ty()
.to_owned()
} else {
args.iter()
.filter(|arg| arg.direction() == Some("in"))
.map(|arg| arg.ty())
.collect::<String>()
};
Ok(Signature::from_string_unchecked(signature))
}
#[cfg(test)]
mod test {
use std::io::{Seek, SeekFrom, Write};
use tempfile::tempfile;
use zbus::zvariant::{OwnedObjectPath, Type};
use crate::get_signal_body_type;
#[test]
fn test_get_signature_of_cache_add_accessible() {
#[derive(Debug, PartialEq, Type)]
struct Accessible {
name: String,
path: OwnedObjectPath,
}
#[derive(Debug, PartialEq, Type)]
struct CacheItem {
obj: Accessible,
application: Accessible,
parent: Accessible,
index_in_parent: i32,
child_count: i32,
interfaces: Vec<String>,
name: String,
role: u32,
description: String,
state_set: Vec<u32>,
}
let xml = r#"<?xml version="1.0" encoding="UTF-8"?>
<node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
<interface name="org.a11y.atspi.Cache">
<signal name="AddAccessible">
<arg name="nodeAdded" type="((so)(so)(so)iiassusau)"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QSpiAccessibleCacheItem"/>
</signal>
</interface>
</node>
"#;
let mut xml_file = tempfile().unwrap();
xml_file.write_all(xml.as_bytes()).unwrap();
xml_file.seek(SeekFrom::Start(0)).unwrap();
let interface_name = "org.a11y.atspi.Cache";
let member_name = "AddAccessible";
let signature = get_signal_body_type(xml_file, interface_name, member_name, None).unwrap();
assert_eq!(signature, CacheItem::signature());
}
}