1#![allow(unused_macros)]
2#![allow(dead_code)]
3#![allow(unused_imports)]
4
5use std::{fs, path::PathBuf, str::FromStr};
6
7use crate::Result;
8
9pub fn resolve_xml_path(xml: Option<&str>) -> Result<PathBuf> {
36 let mut xml = xml;
37 let current_dir: PathBuf = PathBuf::from(
38 std::env::var("CARGO_MANIFEST_DIR")
39 .expect("the CARGO_MANIFEST_DIR environment variable should be set"),
40 );
41
42 let crate_name = std::env::var("CARGO_PKG_NAME").unwrap_or_else(|_| String::from("unknown"));
44
45 let current_dir_lower_case = current_dir.join("xml");
46 let current_dir_upper_case = current_dir.join("XML");
47
48 let parent_dir_lower_case = current_dir.join("../xml");
49 let parent_dir_upper_case = current_dir.join("../XML");
50
51 let crate_dir_lower_case = current_dir.join(&crate_name).join("xml");
52 let crate_dir_upper_case = current_dir.join(&crate_name).join("XML");
53
54 if xml.is_none() {
56 if current_dir_lower_case.exists() {
57 xml = Some(
58 current_dir_lower_case
59 .to_str()
60 .expect("current_dir_lower_case is valid UTF-8"),
61 );
62 }
63
64 if current_dir_upper_case.exists() {
65 xml = Some(
66 current_dir_upper_case
67 .to_str()
68 .expect("current_dir_upper_case is valid UTF-8"),
69 );
70 }
71
72 if parent_dir_lower_case.exists() {
73 xml = Some(
74 parent_dir_lower_case
75 .to_str()
76 .expect("parent_dir_lower_case is valid UTF-8"),
77 );
78 }
79
80 if parent_dir_upper_case.exists() {
81 xml = Some(
82 parent_dir_upper_case
83 .to_str()
84 .expect("parent_dir_upper_case is valid UTF-8"),
85 );
86 }
87
88 if crate_dir_lower_case.exists() {
89 xml = Some(
90 crate_dir_lower_case
91 .to_str()
92 .expect("crate_dir_lower_case is valid UTF-8"),
93 );
94 }
95
96 if crate_dir_upper_case.exists() {
97 xml = Some(
98 crate_dir_upper_case
99 .to_str()
100 .expect("crate_dir_upper_case is valid UTF-8"),
101 );
102 }
103 }
104
105 let env_xml_path = std::env::var("LOCKSTEP_XML_PATH");
106 if env_xml_path.is_ok() {
107 xml = env_xml_path.as_ref().map(|s| s.as_str()).ok();
109 }
110
111 if xml.is_none() {
113 panic!(
114 "No XML path provided and default XML path not found. Current dir: \"{}\" ",
115 current_dir.to_str().expect("current_dir is valid UTF-8")
116 );
117 }
118
119 let xml = PathBuf::from_str(xml.unwrap())?;
121 Ok(xml.canonicalize()?)
122}
123
124#[doc(hidden)]
126#[macro_export]
127macro_rules! find_definition_in_dbus_xml {
128 ($xml_path_buf:expr, $member:expr, $iface:expr, $msg_type:expr) => {{
129 use $crate::MsgType;
130
131 let xml_path_buf: std::path::PathBuf = $xml_path_buf;
132 let member: &str = $member;
133 let iface: Option<String> = $iface;
134 let msg_type: MsgType = $msg_type;
135
136 let mut xml_file_path = None;
137 let mut interface_name = None;
138
139 let read_dir = std::fs::read_dir(&xml_path_buf).expect("Failed to read XML directory");
140
141 for entry in read_dir {
143 let entry = entry.expect("Failed to read entry");
144
145 if entry.path().is_dir() || entry.path().extension().unwrap() != "xml" {
147 continue;
148 }
149
150 let entry_path = entry.path().clone();
151 let file = std::fs::File::open(entry.path()).expect("Failed to open file");
152 let node = $crate::zbus_xml::Node::from_reader(file).expect("Failed to parse XML file");
153
154 for interface in node.interfaces() {
155 if iface.is_some() && interface.name().as_str() != iface.clone().unwrap() {
157 continue;
158 }
159
160 match msg_type {
161 MsgType::Method => {
162 for dbus_item in interface.methods() {
163 if dbus_item.name() == member {
164 if interface_name.is_some() {
165 panic!(
166 "Multiple interfaces offer the same {:?} member: {}, please specify the interface name.",
167 msg_type, member
168 );
169 }
170 interface_name = Some(interface.name().to_string());
171 xml_file_path = Some(entry_path.clone());
172 continue;
173 }
174 }
175 }
176 MsgType::Signal => {
177 for dbus_item in interface.signals() {
178 if dbus_item.name() == member {
179 if interface_name.is_some() {
180 panic!(
181 "Multiple interfaces offer the same {:?} member: {}, please specify the interface name.",
182 msg_type, member
183 );
184 }
185 interface_name = Some(interface.name().to_string());
186 xml_file_path = Some(entry_path.clone());
187 continue;
188 }
189 }
190 }
191 MsgType::Property => {
192 for dbus_item in interface.properties() {
193 if dbus_item.name() == member {
194 if interface_name.is_some() {
195 panic!(
196 "Multiple interfaces offer the same {:?} member: {}, please specify the interface name.",
197 msg_type, member
198 );
199 }
200 interface_name = Some(interface.name().to_string());
201 xml_file_path = Some(entry_path.clone());
202 continue;
203 }
204 }
205 }
206 };
207 }
208 }
209
210 if xml_file_path.is_none() {
212 panic!("Member not found in XML files.");
213 }
214
215 (xml_file_path.unwrap(), interface_name.unwrap())
216 }};
217}
218
219#[macro_export]
262macro_rules! method_return_signature {
263 ($member:expr) => {{
264 use $crate::MsgType;
265 let member = $member;
266
267 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
269 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
270 "Failed to resolve XML path, current dir: {}",
271 current_dir.to_str().unwrap()
272 ));
273
274 let (file_path, interface_name) =
276 $crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Method);
277
278 let file = std::fs::File::open(file_path).expect("Failed to open file");
279 $crate::get_method_return_type(file, &interface_name, member, None)
280 .expect("Failed to get method arguments type signature")
281 }};
282
283 (member: $member:expr) => {
284 $crate::method_return_signature!($member)
285 };
286
287 ($member:expr, $interface:expr) => {{
288 let member = $member;
289 use $crate::MsgType;
290
291 let interface = Some($interface.to_string());
292
293 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
295 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
296 "Failed to resolve XML path, current dir: {}",
297 current_dir.to_str().unwrap()
298 ));
299
300 let (file_path, interface_name) =
302 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method);
303
304 let file = std::fs::File::open(file_path).expect("Failed to open file");
305 $crate::get_method_return_type(file, &interface_name, member, None)
306 .expect("Failed to get method arguments type signature")
307 }};
308
309 (member: $member:expr, interface: $interface:expr) => {
310 $crate::method_return_signature!($member, $interface)
311 };
312
313 ($member:expr, $interface:expr, $argument:expr) => {{
314 let member = $member;
315 use $crate::MsgType;
316
317 let interface = Some($interface.to_string());
318 let argument = Some($argument);
319
320 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
322 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
323 "Failed to resolve XML path, current dir: {}",
324 current_dir.to_str().unwrap()
325 ));
326
327 let (file_path, interface_name) =
329 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method);
330
331 let file = std::fs::File::open(file_path).expect("Failed to open file");
332 $crate::get_method_return_type(file, &interface_name, member, argument)
333 .expect("Failed to get method argument(s) type signature")
334 }};
335
336 (member: $member:expr, interface: $interface:expr, argument: $argument:expr) => {
337 $crate::method_return_signature!($member, $interface, $argument)
338 };
339}
340
341#[macro_export]
382macro_rules! method_args_signature {
383 ($member:expr) => {{
384 use $crate::MsgType;
385 let member = $member;
386
387 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
389 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
390 "Failed to resolve XML path, current dir: {}",
391 current_dir.to_str().unwrap()
392 ));
393
394 let (file_path, interface_name) =
396 $crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Method);
397
398 let file = std::fs::File::open(file_path).expect("Failed to open file");
399 $crate::get_method_args_type(file, &interface_name, member, None)
400 .expect("Failed to get method arguments type signature")
401 }};
402
403 (member: $member:expr) => {
404 $crate::method_args_signature!($member)
405 };
406
407 ($member:expr, $interface:expr) => {{
408 use $crate::MsgType;
409 let member = $member;
410
411 let interface = Some($interface.to_string());
412
413 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
415 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
416 "Failed to resolve XML path, current dir: {}",
417 current_dir.to_str().unwrap()
418 ));
419
420 let (file_path, interface_name) =
422 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method);
423
424 let file = std::fs::File::open(file_path).expect("Failed to open file");
425 $crate::get_method_args_type(file, &interface_name, member, None)
426 .expect("Failed to get method arguments type signature")
427 }};
428
429 (member: $member:expr, interface: $interface:expr) => {
430 $crate::method_args_signature!($member, $interface)
431 };
432
433 ($member:expr, $interface:expr, $argument:expr) => {{
434 use $crate::MsgType;
435 let member = $member;
436 let interface = Some($interface.to_string());
437
438 let argument = Some($argument);
439
440 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
442
443 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
444 "Failed to resolve XML path, current dir: {}",
445 current_dir.to_str().unwrap()
446 ));
447 let (file_path, interface_name) =
449 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method);
450
451 let file = std::fs::File::open(file_path).expect("Failed to open file");
452 $crate::get_method_args_type(file, &interface_name, member, argument)
453 .expect("Failed to get method argument(s) type signature")
454 }};
455
456 (member: $member:expr, interface: $interface:expr, argument: $argument:expr) => {
457 $crate::method_args_signature!($member, $interface, $argument)
458 };
459}
460
461#[macro_export]
499macro_rules! signal_body_type_signature {
500 ($member:expr) => {{
501 use $crate::MsgType;
502 let member = $member;
503
504 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
506 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
507 "Failed to resolve XML path, current dir: {}",
508 current_dir.to_str().unwrap()
509 ));
510
511 let (file_path, interface_name) =
513 $crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Signal);
514
515 let file = std::fs::File::open(file_path).expect("Failed to open file");
516
517 $crate::get_signal_body_type(file, &interface_name, member, None)
518 .expect("Failed to get method arguments type signature")
519 }};
520
521 (member: $member:expr) => {
522 $crate::signal_body_type_signature!($member)
523 };
524
525 ($member:expr, $interface:expr) => {{
526 use $crate::MsgType;
527 let member = $member;
528 let interface = Some($interface.to_string());
529
530 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
532 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
533 "Failed to resolve XML path, current dir: {}",
534 current_dir.to_str().unwrap()
535 ));
536
537 let (file_path, interface_name) =
539 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Signal);
540
541 let file = std::fs::File::open(file_path).expect("Failed to open file");
542 $crate::get_signal_body_type(file, &interface_name, member, None)
543 .expect("Failed to get method arguments type signature")
544 }};
545
546 (member: $member:expr, interface: $interface:expr) => {
547 $crate::signal_body_type_signature!($member, $interface)
548 };
549
550 ($member:expr, $interface:expr, $argument:expr) => {{
551 use $crate::MsgType;
552 let member = $member;
553 let interface = Some($interface.to_string());
554
555 let argument = Some($argument);
556
557 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
559
560 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
561 "Failed to resolve XML path, current dir: {}",
562 current_dir.to_str().unwrap()
563 ));
564
565 let (file_path, interface_name) =
567 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Signal);
568
569 let file = std::fs::File::open(file_path).expect("Failed to open file");
570 $crate::get_signal_body_type(file, &interface_name, member, argument)
571 .expect("Failed to get method argument(s) type signature")
572 }};
573
574 (member: $member:expr, interface: $interface:expr, argument: $argument:expr) => {
575 $crate::signal_body_type_signature!($member, $interface, $argument)
576 };
577}
578
579#[macro_export]
612macro_rules! property_type_signature {
613 ($member:expr) => {{
614 use $crate::MsgType;
615 let member = $member;
616
617 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
619 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
620 "Failed to resolve XML path, current dir: {}",
621 current_dir.to_str().unwrap()
622 ));
623
624 let (file_path, interface_name) =
626 $crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Property);
627
628 let file = std::fs::File::open(file_path).expect("Failed to open file");
629
630 $crate::get_property_type(file, &interface_name, member)
631 .expect("Failed to get property type signature")
632 }};
633
634 (member: $member:expr) => {
635 $crate::property_type_signature!($member)
636 };
637
638 ($member:expr, $interface:expr) => {{
639 use $crate::MsgType;
640 let member = $member;
641 let interface = Some($interface.to_string());
642
643 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
645 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
646 "Failed to resolve XML path, current dir: {}",
647 current_dir.to_str().unwrap()
648 ));
649
650 let (file_path, interface_name) =
652 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Property);
653
654 let file = std::fs::File::open(file_path).expect("Failed to open file");
655 $crate::get_property_type(file, &interface_name, member)
656 .expect("Failed to get property type signature")
657 }};
658
659 (member: $member:expr, interface: $interface:expr) => {
660 $crate::property_type_signature!($member, $interface)
661 };
662}
663
664#[cfg(test)]
665mod test {
666 use std::str::FromStr;
667
668 use zvariant::Signature;
669
670 use crate::signal_body_type_signature;
671
672 #[test]
673 fn test_signal_body_signature_macro() {
674 let sig = crate::signal_body_type_signature!("AddNode");
679 assert_eq!(
680 &sig,
681 &zvariant::Signature::from_str("(so)").expect("Valid signature pattern")
682 );
683 }
684
685 #[test]
686 fn test_signal_body_signature_macro_with_identifier() {
687 let sig = crate::signal_body_type_signature!(member: "AddNode");
688 assert_eq!(
689 sig,
690 Signature::from_str("(so)").expect("Valid signature pattern")
691 );
692 }
693
694 #[test]
695 fn test_signal_body_signature_macro_with_interface() {
696 let sig = crate::signal_body_type_signature!("AddNode", "org.example.Node");
697 assert_eq!(
698 sig,
699 Signature::from_str("(so)").expect("Valid signature pattern")
700 );
701 }
702
703 #[test]
704 fn test_signal_body_signature_macro_with_interface_and_identifiers() {
705 let sig =
706 crate::signal_body_type_signature!(member: "AddNode", interface: "org.example.Node");
707 assert_eq!(
708 sig,
709 Signature::from_str("(so)").expect("Valid signature pattern")
710 );
711 }
712
713 #[test]
714 fn test_signal_body_signature_macro_with_argument_and_interface() {
715 let sig = crate::signal_body_type_signature!("Alert", "org.example.Node", "volume");
716 assert_eq!(
717 sig,
718 Signature::from_str("d").expect("Valid signature pattern")
719 );
720 }
721
722 #[test]
723 fn test_signal_body_signature_macro_with_argument_and_identifiers_and_interface() {
724 let sig = crate::signal_body_type_signature!(
725 member: "Alert",
726 interface: "org.example.Node",
727 argument: "urgent"
728 );
729 assert_eq!(
730 sig,
731 Signature::from_str("b").expect("Valid signature pattern")
732 );
733 }
734
735 #[test]
736 fn test_method_args_signature_macro() {
737 let sig = crate::method_args_signature!("RequestName");
738 assert_eq!(
739 sig,
740 Signature::from_str("(su)").expect("Valid signature pattern")
741 );
742 }
743
744 #[test]
745 fn test_method_args_signature_macro_with_identifier() {
746 let sig = crate::method_args_signature!(member: "RequestName");
747 assert_eq!(
748 sig,
749 Signature::from_str("(su)").expect("Valid signature pattern")
750 );
751 }
752
753 #[test]
754 fn test_method_args_signature_macro_with_interface() {
755 let sig = crate::method_args_signature!("RequestName", "org.example.Node");
756 assert_eq!(
757 sig,
758 Signature::from_str("(su)").expect("Valid signature pattern")
759 );
760 }
761
762 #[test]
763 fn test_method_args_signature_macro_with_interface_and_identifiers() {
764 let sig =
765 crate::method_args_signature!(member: "RequestName", interface: "org.example.Node");
766 assert_eq!(
767 sig,
768 Signature::from_str("(su)").expect("Valid signature pattern")
769 );
770 }
771
772 #[test]
773 fn test_method_args_signature_macro_with_argument_and_interface() {
774 let sig = crate::method_args_signature!("RequestName", "org.example.Node", "apple");
775 assert_eq!(
776 sig,
777 Signature::from_str("s").expect("Valid signature pattern")
778 );
779 }
780
781 #[test]
782 fn test_method_args_signature_macro_with_argument_and_identifiers_and_interface() {
783 let sig = crate::method_args_signature!(
784 member: "RequestName",
785 interface: "org.example.Node",
786 argument: "orange"
787 );
788 assert_eq!(
789 sig,
790 Signature::from_str("u").expect("Valid signature pattern")
791 );
792 }
793
794 #[test]
795 fn test_method_return_signature_macro() {
796 let sig = crate::method_return_signature!("RequestName");
797 assert_eq!(
798 sig,
799 Signature::from_str("u").expect("Valid signatuee pattern")
800 );
801 }
802
803 #[test]
804 fn test_method_return_signature_macro_with_identifier() {
805 let sig = crate::method_return_signature!(member: "RequestName");
806 assert_eq!(
807 sig,
808 Signature::from_str("u").expect("Valid signature pattern")
809 );
810 }
811
812 #[test]
813 fn test_method_return_signature_macro_with_interface() {
814 let sig = crate::method_return_signature!("RequestName", "org.example.Node");
815 assert_eq!(
816 sig,
817 Signature::from_str("u").expect("Valid signature pattern")
818 );
819 }
820
821 #[test]
822 fn test_method_return_signature_macro_with_interface_and_identifiers() {
823 let sig =
824 crate::method_return_signature!(member: "RequestName", interface: "org.example.Node");
825 assert_eq!(
826 sig,
827 Signature::from_str("u").expect("Vlaid signature pattern")
828 );
829 }
830
831 #[test]
832 fn test_method_return_signature_macro_with_argument_and_interface() {
833 let sig = crate::method_return_signature!("RequestName", "org.example.Node", "grape");
834 assert_eq!(
835 sig,
836 Signature::from_str("u").expect("Vlaid signature pattern")
837 );
838 }
839
840 #[test]
841 fn test_method_return_signature_macro_with_argument_and_identifiers_and_interface() {
842 let sig = crate::method_return_signature!(
843 member: "RequestName",
844 interface: "org.example.Node",
845 argument: "grape"
846 );
847 assert_eq!(
848 sig,
849 Signature::from_str("u").expect("Vlaid signature pattern")
850 );
851 }
852
853 #[test]
854 fn test_property_type_signature_macro() {
855 let sig = crate::property_type_signature!("Features");
856 assert_eq!(
857 sig,
858 Signature::from_str("as").expect("Vlaid signature pattern")
859 );
860 }
861
862 #[test]
863 fn test_property_type_signature_macro_with_identifier() {
864 let sig = crate::property_type_signature!(member: "Features");
865 assert_eq!(
866 sig,
867 Signature::from_str("as").expect("Vlaid signature pattern")
868 );
869 }
870
871 #[test]
872 fn test_property_type_signature_macro_with_interface() {
873 let sig = crate::property_type_signature!("Features", "org.example.Node");
874 assert_eq!(
875 sig,
876 Signature::from_str("as").expect("Vlaid signature pattern")
877 );
878 }
879
880 #[test]
881 fn test_property_type_signature_macro_with_interface_and_identifiers() {
882 let sig =
883 crate::property_type_signature!(member: "Features", interface: "org.example.Node");
884 assert_eq!(
885 sig,
886 Signature::from_str("as").expect("Vlaid signature pattern")
887 );
888 }
889}