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 }
173 }
174 }
175 MsgType::Signal => {
176 for dbus_item in interface.signals() {
177 if dbus_item.name() == member {
178 if interface_name.is_some() {
179 panic!(
180 "Multiple interfaces offer the same {:?} member: {}, please specify the interface name.",
181 msg_type, member
182 );
183 }
184 interface_name = Some(interface.name().to_string());
185 xml_file_path = Some(entry_path.clone());
186 }
187 }
188 }
189 MsgType::Property => {
190 for dbus_item in interface.properties() {
191 if dbus_item.name() == member {
192 if interface_name.is_some() {
193 panic!(
194 "Multiple interfaces offer the same {:?} member: {}, please specify the interface name.",
195 msg_type, member
196 );
197 }
198 interface_name = Some(interface.name().to_string());
199 xml_file_path = Some(entry_path.clone());
200 }
201 }
202 }
203 };
204 }
205 }
206
207 if xml_file_path.is_none() {
209 panic!("Member not found in XML files.");
210 }
211
212 (xml_file_path.unwrap(), interface_name.unwrap())
213 }};
214}
215
216#[macro_export]
259macro_rules! method_return_signature {
260 ($member:expr) => {{
261 use $crate::MsgType;
262 let member = $member;
263
264 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
266 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
267 "Failed to resolve XML path, current dir: {}",
268 current_dir.to_str().unwrap()
269 ));
270
271 let (file_path, interface_name) =
273 $crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Method);
274
275 let file = std::fs::File::open(file_path).expect("Failed to open file");
276 $crate::get_method_return_type(file, &interface_name, member, None)
277 .expect("Failed to get method arguments type signature")
278 }};
279
280 (member: $member:expr) => {
281 $crate::method_return_signature!($member)
282 };
283
284 ($member:expr, $interface:expr) => {{
285 let member = $member;
286 use $crate::MsgType;
287
288 let interface = Some($interface.to_string());
289
290 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
292 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
293 "Failed to resolve XML path, current dir: {}",
294 current_dir.to_str().unwrap()
295 ));
296
297 let (file_path, interface_name) =
299 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method);
300
301 let file = std::fs::File::open(file_path).expect("Failed to open file");
302 $crate::get_method_return_type(file, &interface_name, member, None)
303 .expect("Failed to get method arguments type signature")
304 }};
305
306 (member: $member:expr, interface: $interface:expr) => {
307 $crate::method_return_signature!($member, $interface)
308 };
309
310 ($member:expr, $interface:expr, $argument:expr) => {{
311 let member = $member;
312 use $crate::MsgType;
313
314 let interface = Some($interface.to_string());
315 let argument = Some($argument);
316
317 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
319 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
320 "Failed to resolve XML path, current dir: {}",
321 current_dir.to_str().unwrap()
322 ));
323
324 let (file_path, interface_name) =
326 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method);
327
328 let file = std::fs::File::open(file_path).expect("Failed to open file");
329 $crate::get_method_return_type(file, &interface_name, member, argument)
330 .expect("Failed to get method argument(s) type signature")
331 }};
332
333 (member: $member:expr, interface: $interface:expr, argument: $argument:expr) => {
334 $crate::method_return_signature!($member, $interface, $argument)
335 };
336}
337
338#[macro_export]
379macro_rules! method_args_signature {
380 ($member:expr) => {{
381 use $crate::MsgType;
382 let member = $member;
383
384 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
386 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
387 "Failed to resolve XML path, current dir: {}",
388 current_dir.to_str().unwrap()
389 ));
390
391 let (file_path, interface_name) =
393 $crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Method);
394
395 let file = std::fs::File::open(file_path).expect("Failed to open file");
396 $crate::get_method_args_type(file, &interface_name, member, None)
397 .expect("Failed to get method arguments type signature")
398 }};
399
400 (member: $member:expr) => {
401 $crate::method_args_signature!($member)
402 };
403
404 ($member:expr, $interface:expr) => {{
405 use $crate::MsgType;
406 let member = $member;
407
408 let interface = Some($interface.to_string());
409
410 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
412 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
413 "Failed to resolve XML path, current dir: {}",
414 current_dir.to_str().unwrap()
415 ));
416
417 let (file_path, interface_name) =
419 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method);
420
421 let file = std::fs::File::open(file_path).expect("Failed to open file");
422 $crate::get_method_args_type(file, &interface_name, member, None)
423 .expect("Failed to get method arguments type signature")
424 }};
425
426 (member: $member:expr, interface: $interface:expr) => {
427 $crate::method_args_signature!($member, $interface)
428 };
429
430 ($member:expr, $interface:expr, $argument:expr) => {{
431 use $crate::MsgType;
432 let member = $member;
433 let interface = Some($interface.to_string());
434
435 let argument = Some($argument);
436
437 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
439
440 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
441 "Failed to resolve XML path, current dir: {}",
442 current_dir.to_str().unwrap()
443 ));
444 let (file_path, interface_name) =
446 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method);
447
448 let file = std::fs::File::open(file_path).expect("Failed to open file");
449 $crate::get_method_args_type(file, &interface_name, member, argument)
450 .expect("Failed to get method argument(s) type signature")
451 }};
452
453 (member: $member:expr, interface: $interface:expr, argument: $argument:expr) => {
454 $crate::method_args_signature!($member, $interface, $argument)
455 };
456}
457
458#[macro_export]
496macro_rules! signal_body_type_signature {
497 ($member:expr) => {{
498 use $crate::MsgType;
499 let member = $member;
500
501 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
503 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
504 "Failed to resolve XML path, current dir: {}",
505 current_dir.to_str().unwrap()
506 ));
507
508 let (file_path, interface_name) =
510 $crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Signal);
511
512 let file = std::fs::File::open(file_path).expect("Failed to open file");
513
514 $crate::get_signal_body_type(file, &interface_name, member, None)
515 .expect("Failed to get method arguments type signature")
516 }};
517
518 (member: $member:expr) => {
519 $crate::signal_body_type_signature!($member)
520 };
521
522 ($member:expr, $interface:expr) => {{
523 use $crate::MsgType;
524 let member = $member;
525 let interface = Some($interface.to_string());
526
527 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
529 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
530 "Failed to resolve XML path, current dir: {}",
531 current_dir.to_str().unwrap()
532 ));
533
534 let (file_path, interface_name) =
536 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Signal);
537
538 let file = std::fs::File::open(file_path).expect("Failed to open file");
539 $crate::get_signal_body_type(file, &interface_name, member, None)
540 .expect("Failed to get method arguments type signature")
541 }};
542
543 (member: $member:expr, interface: $interface:expr) => {
544 $crate::signal_body_type_signature!($member, $interface)
545 };
546
547 ($member:expr, $interface:expr, $argument:expr) => {{
548 use $crate::MsgType;
549 let member = $member;
550 let interface = Some($interface.to_string());
551
552 let argument = Some($argument);
553
554 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
556
557 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
558 "Failed to resolve XML path, current dir: {}",
559 current_dir.to_str().unwrap()
560 ));
561
562 let (file_path, interface_name) =
564 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Signal);
565
566 let file = std::fs::File::open(file_path).expect("Failed to open file");
567 $crate::get_signal_body_type(file, &interface_name, member, argument)
568 .expect("Failed to get method argument(s) type signature")
569 }};
570
571 (member: $member:expr, interface: $interface:expr, argument: $argument:expr) => {
572 $crate::signal_body_type_signature!($member, $interface, $argument)
573 };
574}
575
576#[macro_export]
609macro_rules! property_type_signature {
610 ($member:expr) => {{
611 use $crate::MsgType;
612 let member = $member;
613
614 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
616 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
617 "Failed to resolve XML path, current dir: {}",
618 current_dir.to_str().unwrap()
619 ));
620
621 let (file_path, interface_name) =
623 $crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Property);
624
625 let file = std::fs::File::open(file_path).expect("Failed to open file");
626
627 $crate::get_property_type(file, &interface_name, member)
628 .expect("Failed to get property type signature")
629 }};
630
631 (member: $member:expr) => {
632 $crate::property_type_signature!($member)
633 };
634
635 ($member:expr, $interface:expr) => {{
636 use $crate::MsgType;
637 let member = $member;
638 let interface = Some($interface.to_string());
639
640 let current_dir: std::path::PathBuf = std::env::current_dir().unwrap();
642 let xml_path = $crate::resolve_xml_path(None).expect(&format!(
643 "Failed to resolve XML path, current dir: {}",
644 current_dir.to_str().unwrap()
645 ));
646
647 let (file_path, interface_name) =
649 $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Property);
650
651 let file = std::fs::File::open(file_path).expect("Failed to open file");
652 $crate::get_property_type(file, &interface_name, member)
653 .expect("Failed to get property type signature")
654 }};
655
656 (member: $member:expr, interface: $interface:expr) => {
657 $crate::property_type_signature!($member, $interface)
658 };
659}
660
661#[cfg(test)]
662mod test {
663 use std::str::FromStr;
664
665 use zvariant::Signature;
666
667 use crate::signal_body_type_signature;
668
669 #[test]
670 fn test_signal_body_signature_macro() {
671 let sig = crate::signal_body_type_signature!("AddNode");
676 assert_eq!(
677 &sig,
678 &zvariant::Signature::from_str("(so)").expect("Valid signature pattern")
679 );
680 }
681
682 #[test]
683 fn test_signal_body_signature_macro_with_identifier() {
684 let sig = crate::signal_body_type_signature!(member: "AddNode");
685 assert_eq!(
686 sig,
687 Signature::from_str("(so)").expect("Valid signature pattern")
688 );
689 }
690
691 #[test]
692 fn test_signal_body_signature_macro_with_interface() {
693 let sig = crate::signal_body_type_signature!("AddNode", "org.example.Node");
694 assert_eq!(
695 sig,
696 Signature::from_str("(so)").expect("Valid signature pattern")
697 );
698 }
699
700 #[test]
701 fn test_signal_body_signature_macro_with_interface_and_identifiers() {
702 let sig =
703 crate::signal_body_type_signature!(member: "AddNode", interface: "org.example.Node");
704 assert_eq!(
705 sig,
706 Signature::from_str("(so)").expect("Valid signature pattern")
707 );
708 }
709
710 #[test]
711 fn test_signal_body_signature_macro_with_argument_and_interface() {
712 let sig = crate::signal_body_type_signature!("Alert", "org.example.Node", "volume");
713 assert_eq!(
714 sig,
715 Signature::from_str("d").expect("Valid signature pattern")
716 );
717 }
718
719 #[test]
720 fn test_signal_body_signature_macro_with_argument_and_identifiers_and_interface() {
721 let sig = crate::signal_body_type_signature!(
722 member: "Alert",
723 interface: "org.example.Node",
724 argument: "urgent"
725 );
726 assert_eq!(
727 sig,
728 Signature::from_str("b").expect("Valid signature pattern")
729 );
730 }
731
732 #[test]
733 fn test_method_args_signature_macro() {
734 let sig = crate::method_args_signature!("RequestName");
735 assert_eq!(
736 sig,
737 Signature::from_str("(su)").expect("Valid signature pattern")
738 );
739 }
740
741 #[test]
742 fn test_method_args_signature_macro_with_identifier() {
743 let sig = crate::method_args_signature!(member: "RequestName");
744 assert_eq!(
745 sig,
746 Signature::from_str("(su)").expect("Valid signature pattern")
747 );
748 }
749
750 #[test]
751 fn test_method_args_signature_macro_with_interface() {
752 let sig = crate::method_args_signature!("RequestName", "org.example.Node");
753 assert_eq!(
754 sig,
755 Signature::from_str("(su)").expect("Valid signature pattern")
756 );
757 }
758
759 #[test]
760 fn test_method_args_signature_macro_with_interface_and_identifiers() {
761 let sig =
762 crate::method_args_signature!(member: "RequestName", interface: "org.example.Node");
763 assert_eq!(
764 sig,
765 Signature::from_str("(su)").expect("Valid signature pattern")
766 );
767 }
768
769 #[test]
770 fn test_method_args_signature_macro_with_argument_and_interface() {
771 let sig = crate::method_args_signature!("RequestName", "org.example.Node", "apple");
772 assert_eq!(
773 sig,
774 Signature::from_str("s").expect("Valid signature pattern")
775 );
776 }
777
778 #[test]
779 fn test_method_args_signature_macro_with_argument_and_identifiers_and_interface() {
780 let sig = crate::method_args_signature!(
781 member: "RequestName",
782 interface: "org.example.Node",
783 argument: "orange"
784 );
785 assert_eq!(
786 sig,
787 Signature::from_str("u").expect("Valid signature pattern")
788 );
789 }
790
791 #[test]
792 fn test_method_return_signature_macro() {
793 let sig = crate::method_return_signature!("RequestName");
794 assert_eq!(
795 sig,
796 Signature::from_str("u").expect("Valid signatuee pattern")
797 );
798 }
799
800 #[test]
801 fn test_method_return_signature_macro_with_identifier() {
802 let sig = crate::method_return_signature!(member: "RequestName");
803 assert_eq!(
804 sig,
805 Signature::from_str("u").expect("Valid signature pattern")
806 );
807 }
808
809 #[test]
810 fn test_method_return_signature_macro_with_interface() {
811 let sig = crate::method_return_signature!("RequestName", "org.example.Node");
812 assert_eq!(
813 sig,
814 Signature::from_str("u").expect("Valid signature pattern")
815 );
816 }
817
818 #[test]
819 fn test_method_return_signature_macro_with_interface_and_identifiers() {
820 let sig =
821 crate::method_return_signature!(member: "RequestName", interface: "org.example.Node");
822 assert_eq!(
823 sig,
824 Signature::from_str("u").expect("Vlaid signature pattern")
825 );
826 }
827
828 #[test]
829 fn test_method_return_signature_macro_with_argument_and_interface() {
830 let sig = crate::method_return_signature!("RequestName", "org.example.Node", "grape");
831 assert_eq!(
832 sig,
833 Signature::from_str("u").expect("Vlaid signature pattern")
834 );
835 }
836
837 #[test]
838 fn test_method_return_signature_macro_with_argument_and_identifiers_and_interface() {
839 let sig = crate::method_return_signature!(
840 member: "RequestName",
841 interface: "org.example.Node",
842 argument: "grape"
843 );
844 assert_eq!(
845 sig,
846 Signature::from_str("u").expect("Vlaid signature pattern")
847 );
848 }
849
850 #[test]
851 fn test_property_type_signature_macro() {
852 let sig = crate::property_type_signature!("Features");
853 assert_eq!(
854 sig,
855 Signature::from_str("as").expect("Vlaid signature pattern")
856 );
857 }
858
859 #[test]
860 fn test_property_type_signature_macro_with_identifier() {
861 let sig = crate::property_type_signature!(member: "Features");
862 assert_eq!(
863 sig,
864 Signature::from_str("as").expect("Vlaid signature pattern")
865 );
866 }
867
868 #[test]
869 fn test_property_type_signature_macro_with_interface() {
870 let sig = crate::property_type_signature!("Features", "org.example.Node");
871 assert_eq!(
872 sig,
873 Signature::from_str("as").expect("Vlaid signature pattern")
874 );
875 }
876
877 #[test]
878 fn test_property_type_signature_macro_with_interface_and_identifiers() {
879 let sig =
880 crate::property_type_signature!(member: "Features", interface: "org.example.Node");
881 assert_eq!(
882 sig,
883 Signature::from_str("as").expect("Vlaid signature pattern")
884 );
885 }
886}