#![allow(unused_macros)]
#![allow(dead_code)]
#![allow(unused_imports)]
use std::{fs, path::PathBuf, str::FromStr};
use zbus::xml;
use crate::Result;
pub fn resolve_xml_path(xml: Option<&str>) -> Result<PathBuf> {
let mut xml = xml;
let current_dir: PathBuf = std::env::current_dir()?;
let default_xml_path = current_dir.join("xml");
let default_xml_path_alt = current_dir.join("XML");
if xml.is_none() {
if default_xml_path.exists() {
xml = Some(
default_xml_path
.to_str()
.expect("default_xml_path is valid UTF-8"),
);
}
if default_xml_path_alt.exists() {
xml = Some(
default_xml_path_alt
.to_str()
.expect("default_xml_path is valid UTF-8"),
);
}
}
let env_xml_path = std::env::var("LOCKSTEP_XML_PATH");
if env_xml_path.is_ok() {
xml = env_xml_path.as_ref().map(|s| s.as_str()).ok();
}
if xml.is_none() {
panic!("No XML path provided and default XML path not found.");
}
let xml = PathBuf::from_str(xml.unwrap())?;
Ok(xml.canonicalize()?)
}
#[doc(hidden)]
#[macro_export]
macro_rules! find_definition_in_dbus_xml {
($xml_path_buf:expr, $member:expr, $iface:expr, $msg_type:expr) => {{
use zbus_lockstep::MsgType;
let xml_path_buf: std::path::PathBuf = $xml_path_buf;
let member: &str = $member;
let iface: Option<String> = $iface;
let msg_type: zbus_lockstep::MsgType = $msg_type;
let mut xml_file_path = None;
let mut interface_name = None;
let read_dir = std::fs::read_dir(&xml_path_buf).expect("Failed to read XML directory");
for entry in read_dir {
let entry = entry.expect("Failed to read entry");
if entry.path().is_dir() || entry.path().extension().unwrap() != "xml" {
continue;
}
let entry_path = entry.path().clone();
let xml_string = std::fs::read_to_string(entry.path()).expect("Failed to read XML file");
let node = <zbus::xml::Node as std::str::FromStr>::from_str(&xml_string).expect("Failed to parse XML file");
for interface in node.interfaces() {
if iface.is_some() && interface.name() != iface.clone().unwrap() {
continue;
}
match msg_type {
MsgType::Method => {
for dbus_item in interface.methods() {
if dbus_item.name() == member {
if interface_name.is_some() {
panic!(
"Multiple interfaces offer the same {:?} member: {}, please specify the interface name.",
msg_type, member
);
}
interface_name = Some(interface.name().to_string());
xml_file_path = Some(entry_path.clone());
continue;
}
}
}
MsgType::Signal => {
for dbus_item in interface.signals() {
if dbus_item.name() == member {
if interface_name.is_some() {
panic!(
"Multiple interfaces offer the same {:?} member: {}, please specify the interface name.",
msg_type, member
);
}
interface_name = Some(interface.name().to_string());
xml_file_path = Some(entry_path.clone());
continue;
}
}
}
MsgType::Property => {
for dbus_item in interface.properties() {
if dbus_item.name() == member {
if interface_name.is_some() {
panic!(
"Multiple interfaces offer the same {:?} member: {}, please specify the interface name.",
msg_type, member
);
}
interface_name = Some(interface.name().to_string());
xml_file_path = Some(entry_path.clone());
continue;
}
}
}
};
}
}
if xml_file_path.is_none() {
panic!("Member not found in XML files.");
}
(xml_file_path.unwrap(), interface_name.unwrap())
}};
}
#[macro_export]
macro_rules! assert_eq_signatures {
($lhs_sig:expr, $rhs_sig:expr) => {
assert!(
zbus_lockstep::signatures_are_eq($lhs_sig, $rhs_sig),
"Signatures are not equal (Lhs: {}, Rhs: {})",
$lhs_sig,
$rhs_sig
);
};
}
#[macro_export]
macro_rules! assert_ne_signatures {
($lhs_sig:expr, $rhs_sig:expr) => {
assert!(
!zbus_lockstep::signatures_are_eq($lhs_sig, $rhs_sig),
"Signatures are equal (Lhs: {}, Rhs: {})",
$lhs_sig,
$rhs_sig
);
};
}
#[macro_export]
macro_rules! method_return_signature {
($member:expr) => {{
let member = $member;
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = zbus_lockstep::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
zbus_lockstep::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Method);
let file = std::fs::File::open(file_path).expect("Failed to open file");
zbus_lockstep::get_method_return_type(file, &interface_name, member, None)
.expect("Failed to get method arguments type signature")
}};
(member: $member:expr) => {
method_return_signature!($member)
};
($member:expr, $interface:expr) => {{
let member = $member;
let interface = Some($interface.to_string());
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = zbus_lockstep::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) = zbus_lockstep::find_definition_in_dbus_xml!(
xml_path,
member,
interface,
MsgType::Method
);
let file = std::fs::File::open(file_path).expect("Failed to open file");
zbus_lockstep::get_method_return_type(file, &interface_name, member, None)
.expect("Failed to get method arguments type signature")
}};
(member: $member:expr, interface: $interface:expr) => {
method_return_signature!($member, $interface)
};
($member:expr, $interface:expr, $argument:expr) => {{
let member = $member;
let interface = Some($interface.to_string());
let argument = Some($argument);
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = zbus_lockstep::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) = zbus_lockstep::find_definition_in_dbus_xml!(
xml_path,
member,
interface,
MsgType::Method
);
let file = std::fs::File::open(file_path).expect("Failed to open file");
zbus_lockstep::get_method_return_type(file, &interface_name, member, argument)
.expect("Failed to get method argument(s) type signature")
}};
(member: $member:expr, interface: $interface:expr, argument: $argument:expr) => {
method_return_signature!($member, $interface, $argument)
};
}
#[macro_export]
macro_rules! method_args_signature {
($member:expr) => {{
let member = $member;
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = zbus_lockstep::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
zbus_lockstep::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Method);
let file = std::fs::File::open(file_path).expect("Failed to open file");
zbus_lockstep::get_method_args_type(file, &interface_name, member, None)
.expect("Failed to get method arguments type signature")
}};
(member: $member:expr) => {
method_args_signature!($member)
};
($member:expr, $interface:expr) => {{
let member = $member;
let interface = Some($interface.to_string());
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = zbus_lockstep::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) = zbus_lockstep::find_definition_in_dbus_xml!(
xml_path,
member,
interface,
MsgType::Method
);
let file = std::fs::File::open(file_path).expect("Failed to open file");
zbus_lockstep::get_method_args_type(file, &interface_name, member, None)
.expect("Failed to get method arguments type signature")
}};
(member: $member:expr, interface: $interface:expr) => {
method_args_signature!($member, $interface)
};
($member:expr, $interface:expr, $argument:expr) => {{
let member = $member;
let interface = Some($interface.to_string());
let argument = Some($argument);
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = zbus_lockstep::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) = zbus_lockstep::find_definition_in_dbus_xml!(
xml_path,
member,
interface,
MsgType::Method
);
let file = std::fs::File::open(file_path).expect("Failed to open file");
zbus_lockstep::get_method_args_type(file, &interface_name, member, argument)
.expect("Failed to get method argument(s) type signature")
}};
(member: $member:expr, interface: $interface:expr, argument: $argument:expr) => {
method_args_signature!($member, $interface, $argument)
};
}
#[macro_export]
macro_rules! signal_body_type_signature {
($member:expr) => {{
let member = $member;
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = zbus_lockstep::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
zbus_lockstep::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Signal);
let file = std::fs::File::open(file_path).expect("Failed to open file");
zbus_lockstep::get_signal_body_type(file, &interface_name, member, None)
.expect("Failed to get method arguments type signature")
}};
(member: $member:expr) => {
signal_body_type_signature!($member)
};
($member:expr, $interface:expr) => {{
let member = $member;
let interface = Some($interface.to_string());
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = zbus_lockstep::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) = zbus_lockstep::find_definition_in_dbus_xml!(
xml_path,
member,
interface,
MsgType::Signal
);
let file = std::fs::File::open(file_path).expect("Failed to open file");
zbus_lockstep::get_signal_body_type(file, &interface_name, member, None)
.expect("Failed to get method arguments type signature")
}};
(member: $member:expr, interface: $interface:expr) => {
signal_body_type_signature!($member, $interface)
};
($member:expr, $interface:expr, $argument:expr) => {{
let member = $member;
let interface = Some($interface.to_string());
let argument = Some($argument);
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = zbus_lockstep::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) = zbus_lockstep::find_definition_in_dbus_xml!(
xml_path,
member,
interface,
MsgType::Signal
);
let file = std::fs::File::open(file_path).expect("Failed to open file");
zbus_lockstep::get_signal_body_type(file, &interface_name, member, argument)
.expect("Failed to get method argument(s) type signature")
}};
(member: $member:expr, interface: $interface:expr, argument: $argument:expr) => {
signal_body_type_signature!($member, $interface, $argument)
};
}
#[macro_export]
macro_rules! property_type_signature {
($member:expr) => {{
let member = $member;
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = zbus_lockstep::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
zbus_lockstep::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Property);
let file = std::fs::File::open(file_path).expect("Failed to open file");
zbus_lockstep::get_property_type(file, &interface_name, member)
.expect("Failed to get property type signature")
}};
(member: $member:expr) => {
property_type_signature!($member)
};
($member:expr, $interface:expr) => {{
let member = $member;
let interface = Some($interface.to_string());
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = zbus_lockstep::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) = zbus_lockstep::find_definition_in_dbus_xml!(
xml_path,
member,
interface,
MsgType::Property
);
let file = std::fs::File::open(file_path).expect("Failed to open file");
zbus_lockstep::get_property_type(file, &interface_name, member)
.expect("Failed to get property type signature")
}};
(member: $member:expr, interface: $interface:expr) => {
property_type_signature!($member, $interface)
};
}
#[cfg(test)]
mod test {
use zbus::zvariant::Signature;
use crate as zbus_lockstep;
use crate::{signal_body_type_signature, utils::signatures_are_eq};
#[test]
fn test_assert_eq_signatures() {
let sig1 = Signature::from_str_unchecked("(ii)(ii)");
let sig2 = Signature::from_str_unchecked("((ii)(ii))");
assert_eq_signatures!(&sig1, &sig2);
let sig1 = Signature::from_str_unchecked("a{sv}");
let sig2 = Signature::from_str_unchecked("a{sv}");
assert_eq_signatures!(&sig1, &sig2);
let sig1 = Signature::from_str_unchecked("a{sv}");
let sig2 = Signature::from_str_unchecked("(a{sv})");
assert_eq_signatures!(&sig1, &sig2);
let sig1 = Signature::from_str_unchecked("(ii)(ii)");
let sig2 = Signature::from_str_unchecked("((ii)(ii))");
assert_eq_signatures!(&sig1, &sig2);
}
#[test]
#[should_panic]
fn test_assert_eq_signatures_panic() {
let sig1 = Signature::from_str_unchecked("(ii)(ii)");
let sig2 = Signature::from_str_unchecked("ii)(ii");
assert_eq_signatures!(&sig1, &sig2);
}
#[test]
fn test_assert_ne_signatures() {
let sig1 = Signature::from_str_unchecked("(ii)");
let sig2 = Signature::from_str_unchecked("(uu)");
assert_ne_signatures!(&sig1, &sig2);
let sig1 = Signature::from_str_unchecked("a{sv}");
let sig2 = Signature::from_str_unchecked("((a{sv}))");
assert_ne_signatures!(&sig1, &sig2);
let sig1 = Signature::from_str_unchecked("(ii(ii))");
let sig2 = Signature::from_str_unchecked("((ii)(ii))");
assert_ne_signatures!(&sig1, &sig2);
}
#[test]
#[should_panic]
fn test_assert_ne_signatures_panic() {
let sig1 = Signature::from_str_unchecked("(ii)(ii)");
let sig2 = Signature::from_str_unchecked("((ii)(ii))");
assert_ne_signatures!(&sig1, &sig2);
}
#[test]
fn test_signal_body_signature_macro() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::signal_body_type_signature!("AddNode");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("(so)"));
}
#[test]
fn test_signal_body_signature_macro_with_identifier() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::signal_body_type_signature!(member: "AddNode");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("(so)"));
}
#[test]
fn test_signal_body_signature_macro_with_interface() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::signal_body_type_signature!("AddNode", "org.example.Node");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("(so)"));
}
#[test]
fn test_signal_body_signature_macro_with_interface_and_identifiers() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::signal_body_type_signature!(member: "AddNode", interface: "org.example.Node");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("(so)"));
}
#[test]
fn test_signal_body_signature_macro_with_argument_and_interface() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::signal_body_type_signature!("Alert", "org.example.Node", "volume");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("d"));
}
#[test]
fn test_signal_body_signature_macro_with_argument_and_identifiers_and_interface() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::signal_body_type_signature!(
member: "Alert",
interface: "org.example.Node",
argument: "urgent"
);
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("b"));
}
#[test]
fn test_method_args_signature_macro() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::method_args_signature!("RequestName");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("(su)"));
}
#[test]
fn test_method_args_signature_macro_with_identifier() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::method_args_signature!(member: "RequestName");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("(su)"));
}
#[test]
fn test_method_args_signature_macro_with_interface() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::method_args_signature!("RequestName", "org.example.Node");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("(su)"));
}
#[test]
fn test_method_args_signature_macro_with_interface_and_identifiers() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::method_args_signature!(member: "RequestName", interface: "org.example.Node");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("(su)"));
}
#[test]
fn test_method_args_signature_macro_with_argument_and_interface() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::method_args_signature!("RequestName", "org.example.Node", "apple");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("s"));
}
#[test]
fn test_method_args_signature_macro_with_argument_and_identifiers_and_interface() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::method_args_signature!(
member: "RequestName",
interface: "org.example.Node",
argument: "orange"
);
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("u"));
}
#[test]
fn test_method_return_signature_macro() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::method_return_signature!("RequestName");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("u"));
}
#[test]
fn test_method_return_signature_macro_with_identifier() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::method_return_signature!(member: "RequestName");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("u"));
}
#[test]
fn test_method_return_signature_macro_with_interface() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::method_return_signature!("RequestName", "org.example.Node");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("u"));
}
#[test]
fn test_method_return_signature_macro_with_interface_and_identifiers() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::method_return_signature!(member: "RequestName", interface: "org.example.Node");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("u"));
}
#[test]
fn test_method_return_signature_macro_with_argument_and_interface() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig =
zbus_lockstep::method_return_signature!("RequestName", "org.example.Node", "grape");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("u"));
}
#[test]
fn test_method_return_signature_macro_with_argument_and_identifiers_and_interface() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::method_return_signature!(
member: "RequestName",
interface: "org.example.Node",
argument: "grape"
);
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("u"));
}
#[test]
fn test_property_type_signature_macro() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::property_type_signature!("Features");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("as"));
}
#[test]
fn test_property_type_signature_macro_with_identifier() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::property_type_signature!(member: "Features");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("as"));
}
#[test]
fn test_property_type_signature_macro_with_interface() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::property_type_signature!("Features", "org.example.Node");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("as"));
}
#[test]
fn test_property_type_signature_macro_with_interface_and_identifiers() {
std::env::set_var("LOCKSTEP_XML_PATH", "../xml");
let sig = zbus_lockstep::property_type_signature!(member: "Features", interface: "org.example.Node");
assert_eq_signatures!(&sig, &zbus::zvariant::Signature::from_str_unchecked("as"));
}
}