#![allow(unused_macros)]
#![allow(dead_code)]
#![allow(unused_imports)]
use std::{fs, path::PathBuf, str::FromStr};
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 crate_name = std::env::var("CARGO_PKG_NAME").unwrap_or_else(|_| String::from("unknown"));
let current_dir_lower_case = current_dir.join("xml");
let current_dir_upper_case = current_dir.join("XML");
let parent_dir_lower_case = current_dir.join("../xml");
let parent_dir_upper_case = current_dir.join("../XML");
let crate_dir_lower_case = current_dir.join(&crate_name).join("xml");
let crate_dir_upper_case = current_dir.join(&crate_name).join("XML");
if xml.is_none() {
if current_dir_lower_case.exists() {
xml = Some(
current_dir_lower_case
.to_str()
.expect("current_dir_lower_case is valid UTF-8"),
);
}
if current_dir_upper_case.exists() {
xml = Some(
current_dir_upper_case
.to_str()
.expect("current_dir_upper_case is valid UTF-8"),
);
}
if parent_dir_lower_case.exists() {
xml = Some(
parent_dir_lower_case
.to_str()
.expect("parent_dir_lower_case is valid UTF-8"),
);
}
if parent_dir_upper_case.exists() {
xml = Some(
parent_dir_upper_case
.to_str()
.expect("parent_dir_upper_case is valid UTF-8"),
);
}
if crate_dir_lower_case.exists() {
xml = Some(
crate_dir_lower_case
.to_str()
.expect("crate_dir_lower_case is valid UTF-8"),
);
}
if crate_dir_upper_case.exists() {
xml = Some(
crate_dir_upper_case
.to_str()
.expect("crate_dir_upper_case 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. Current dir: \"{}\" ",
current_dir.to_str().expect("current_dir is valid UTF-8")
);
}
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 $crate::MsgType;
let xml_path_buf: std::path::PathBuf = $xml_path_buf;
let member: &str = $member;
let iface: Option<String> = $iface;
let msg_type: 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 file = std::fs::File::open(entry.path()).expect("Failed to open file");
let node = $crate::zbus_xml::Node::from_reader(file).expect("Failed to parse XML file");
for interface in node.interfaces() {
if iface.is_some() && interface.name().as_str() != 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! method_return_signature {
($member:expr) => {{
use $crate::MsgType;
let member = $member;
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = $crate::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
$crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Method);
let file = std::fs::File::open(file_path).expect("Failed to open file");
$crate::get_method_return_type(file, &interface_name, member, None)
.expect("Failed to get method arguments type signature")
}};
(member: $member:expr) => {
$crate::method_return_signature!($member)
};
($member:expr, $interface:expr) => {{
let member = $member;
use $crate::MsgType;
let interface = Some($interface.to_string());
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = $crate::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
$crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method);
let file = std::fs::File::open(file_path).expect("Failed to open file");
$crate::get_method_return_type(file, &interface_name, member, None)
.expect("Failed to get method arguments type signature")
}};
(member: $member:expr, interface: $interface:expr) => {
$crate::method_return_signature!($member, $interface)
};
($member:expr, $interface:expr, $argument:expr) => {{
let member = $member;
use $crate::MsgType;
let interface = Some($interface.to_string());
let argument = Some($argument);
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = $crate::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
$crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method);
let file = std::fs::File::open(file_path).expect("Failed to open file");
$crate::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) => {
$crate::method_return_signature!($member, $interface, $argument)
};
}
#[macro_export]
macro_rules! method_args_signature {
($member:expr) => {{
use $crate::MsgType;
let member = $member;
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = $crate::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
$crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Method);
let file = std::fs::File::open(file_path).expect("Failed to open file");
$crate::get_method_args_type(file, &interface_name, member, None)
.expect("Failed to get method arguments type signature")
}};
(member: $member:expr) => {
$crate::method_args_signature!($member)
};
($member:expr, $interface:expr) => {{
use $crate::MsgType;
let member = $member;
let interface = Some($interface.to_string());
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = $crate::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
$crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method);
let file = std::fs::File::open(file_path).expect("Failed to open file");
$crate::get_method_args_type(file, &interface_name, member, None)
.expect("Failed to get method arguments type signature")
}};
(member: $member:expr, interface: $interface:expr) => {
$crate::method_args_signature!($member, $interface)
};
($member:expr, $interface:expr, $argument:expr) => {{
use $crate::MsgType;
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 = $crate::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
$crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method);
let file = std::fs::File::open(file_path).expect("Failed to open file");
$crate::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) => {
$crate::method_args_signature!($member, $interface, $argument)
};
}
#[macro_export]
macro_rules! signal_body_type_signature {
($member:expr) => {{
use $crate::MsgType;
let member = $member;
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = $crate::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
$crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Signal);
let file = std::fs::File::open(file_path).expect("Failed to open file");
$crate::get_signal_body_type(file, &interface_name, member, None)
.expect("Failed to get method arguments type signature")
}};
(member: $member:expr) => {
$crate::signal_body_type_signature!($member)
};
($member:expr, $interface:expr) => {{
use $crate::MsgType;
let member = $member;
let interface = Some($interface.to_string());
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = $crate::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
$crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Signal);
let file = std::fs::File::open(file_path).expect("Failed to open file");
$crate::get_signal_body_type(file, &interface_name, member, None)
.expect("Failed to get method arguments type signature")
}};
(member: $member:expr, interface: $interface:expr) => {
$crate::signal_body_type_signature!($member, $interface)
};
($member:expr, $interface:expr, $argument:expr) => {{
use $crate::MsgType;
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 = $crate::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
$crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Signal);
let file = std::fs::File::open(file_path).expect("Failed to open file");
$crate::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) => {
$crate::signal_body_type_signature!($member, $interface, $argument)
};
}
#[macro_export]
macro_rules! property_type_signature {
($member:expr) => {{
use $crate::MsgType;
let member = $member;
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = $crate::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
$crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Property);
let file = std::fs::File::open(file_path).expect("Failed to open file");
$crate::get_property_type(file, &interface_name, member)
.expect("Failed to get property type signature")
}};
(member: $member:expr) => {
$crate::property_type_signature!($member)
};
($member:expr, $interface:expr) => {{
use $crate::MsgType;
let member = $member;
let interface = Some($interface.to_string());
let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
let xml_path = $crate::resolve_xml_path(None).expect(&format!(
"Failed to resolve XML path, current dir: {}",
current_dir.to_str().unwrap()
));
let (file_path, interface_name) =
$crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Property);
let file = std::fs::File::open(file_path).expect("Failed to open file");
$crate::get_property_type(file, &interface_name, member)
.expect("Failed to get property type signature")
}};
(member: $member:expr, interface: $interface:expr) => {
$crate::property_type_signature!($member, $interface)
};
}
#[cfg(test)]
mod test {
use zvariant::Signature;
use crate::signal_body_type_signature;
#[test]
fn test_signal_body_signature_macro() {
let sig = crate::signal_body_type_signature!("AddNode");
assert_eq!(&sig, &zvariant::Signature::from_str_unchecked("(so)"));
}
#[test]
fn test_signal_body_signature_macro_with_identifier() {
let sig = crate::signal_body_type_signature!(member: "AddNode");
assert_eq!(sig, Signature::from_str_unchecked("(so)"));
}
#[test]
fn test_signal_body_signature_macro_with_interface() {
let sig = crate::signal_body_type_signature!("AddNode", "org.example.Node");
assert_eq!(sig, Signature::from_str_unchecked("(so)"));
}
#[test]
fn test_signal_body_signature_macro_with_interface_and_identifiers() {
let sig =
crate::signal_body_type_signature!(member: "AddNode", interface: "org.example.Node");
assert_eq!(sig, Signature::from_str_unchecked("(so)"));
}
#[test]
fn test_signal_body_signature_macro_with_argument_and_interface() {
let sig = crate::signal_body_type_signature!("Alert", "org.example.Node", "volume");
assert_eq!(sig, Signature::from_str_unchecked("d"));
}
#[test]
fn test_signal_body_signature_macro_with_argument_and_identifiers_and_interface() {
let sig = crate::signal_body_type_signature!(
member: "Alert",
interface: "org.example.Node",
argument: "urgent"
);
assert_eq!(sig, Signature::from_str_unchecked("b"));
}
#[test]
fn test_method_args_signature_macro() {
let sig = crate::method_args_signature!("RequestName");
assert_eq!(sig, Signature::from_str_unchecked("(su)"));
}
#[test]
fn test_method_args_signature_macro_with_identifier() {
let sig = crate::method_args_signature!(member: "RequestName");
assert_eq!(sig, Signature::from_str_unchecked("(su)"));
}
#[test]
fn test_method_args_signature_macro_with_interface() {
let sig = crate::method_args_signature!("RequestName", "org.example.Node");
assert_eq!(sig, Signature::from_str_unchecked("(su)"));
}
#[test]
fn test_method_args_signature_macro_with_interface_and_identifiers() {
let sig =
crate::method_args_signature!(member: "RequestName", interface: "org.example.Node");
assert_eq!(sig, Signature::from_str_unchecked("(su)"));
}
#[test]
fn test_method_args_signature_macro_with_argument_and_interface() {
let sig = crate::method_args_signature!("RequestName", "org.example.Node", "apple");
assert_eq!(sig, Signature::from_str_unchecked("s"));
}
#[test]
fn test_method_args_signature_macro_with_argument_and_identifiers_and_interface() {
let sig = crate::method_args_signature!(
member: "RequestName",
interface: "org.example.Node",
argument: "orange"
);
assert_eq!(sig, Signature::from_str_unchecked("u"));
}
#[test]
fn test_method_return_signature_macro() {
let sig = crate::method_return_signature!("RequestName");
assert_eq!(sig, Signature::from_str_unchecked("u"));
}
#[test]
fn test_method_return_signature_macro_with_identifier() {
let sig = crate::method_return_signature!(member: "RequestName");
assert_eq!(sig, Signature::from_str_unchecked("u"));
}
#[test]
fn test_method_return_signature_macro_with_interface() {
let sig = crate::method_return_signature!("RequestName", "org.example.Node");
assert_eq!(sig, Signature::from_str_unchecked("u"));
}
#[test]
fn test_method_return_signature_macro_with_interface_and_identifiers() {
let sig =
crate::method_return_signature!(member: "RequestName", interface: "org.example.Node");
assert_eq!(sig, Signature::from_str_unchecked("u"));
}
#[test]
fn test_method_return_signature_macro_with_argument_and_interface() {
let sig = crate::method_return_signature!("RequestName", "org.example.Node", "grape");
assert_eq!(sig, Signature::from_str_unchecked("u"));
}
#[test]
fn test_method_return_signature_macro_with_argument_and_identifiers_and_interface() {
let sig = crate::method_return_signature!(
member: "RequestName",
interface: "org.example.Node",
argument: "grape"
);
assert_eq!(sig, Signature::from_str_unchecked("u"));
}
#[test]
fn test_property_type_signature_macro() {
let sig = crate::property_type_signature!("Features");
assert_eq!(sig, Signature::from_str_unchecked("as"));
}
#[test]
fn test_property_type_signature_macro_with_identifier() {
let sig = crate::property_type_signature!(member: "Features");
assert_eq!(sig, Signature::from_str_unchecked("as"));
}
#[test]
fn test_property_type_signature_macro_with_interface() {
let sig = crate::property_type_signature!("Features", "org.example.Node");
assert_eq!(sig, Signature::from_str_unchecked("as"));
}
#[test]
fn test_property_type_signature_macro_with_interface_and_identifiers() {
let sig =
crate::property_type_signature!(member: "Features", interface: "org.example.Node");
assert_eq!(sig, Signature::from_str_unchecked("as"));
}
}