1 | #![allow (unused_macros)] |
2 | #![allow (dead_code)] |
3 | #![allow (unused_imports)] |
4 | |
5 | use std::{fs, path::PathBuf, str::FromStr}; |
6 | |
7 | use crate::Result; |
8 | |
9 | /// Resolve XML path from either: |
10 | /// |
11 | /// - provided argument, |
12 | /// - default location (`xml/`, `XML/`, `../xml` or `../XML`) or |
13 | /// - env_variable (`LOCKSTEP_XML_PATH`) |
14 | /// |
15 | /// If no XML path is provided, it tries to find the default XML path. |
16 | /// If the environment variable is set, it overrides the default, or |
17 | /// argument path. |
18 | /// |
19 | /// # Example |
20 | /// |
21 | /// ```rust |
22 | /// # use zbus_lockstep::resolve_xml_path; |
23 | /// # use std::path::PathBuf; |
24 | /// # fn main() { |
25 | /// // path to XML files |
26 | /// std::env::set_var("LOCKSTEP_XML_PATH" , "../xml" ); |
27 | /// |
28 | /// let xml_path = resolve_xml_path(None).unwrap(); |
29 | /// assert_eq!(xml_path, PathBuf::from("../xml" ).canonicalize().unwrap()); |
30 | /// # } |
31 | /// ``` |
32 | /// # Panics |
33 | /// |
34 | /// Panics if no XML path is provided and the default XML path is not found. |
35 | pub fn resolve_xml_path(xml: Option<&str>) -> Result<PathBuf> { |
36 | let mut xml = xml; |
37 | let current_dir: PathBuf = std::env::current_dir()?; |
38 | |
39 | // We want to know the name of the crate we are expanded in. |
40 | let crate_name = std::env::var("CARGO_PKG_NAME" ).unwrap_or_else(|_| String::from("unknown" )); |
41 | |
42 | let current_dir_lower_case = current_dir.join("xml" ); |
43 | let current_dir_upper_case = current_dir.join("XML" ); |
44 | |
45 | let parent_dir_lower_case = current_dir.join("../xml" ); |
46 | let parent_dir_upper_case = current_dir.join("../XML" ); |
47 | |
48 | let crate_dir_lower_case = current_dir.join(&crate_name).join("xml" ); |
49 | let crate_dir_upper_case = current_dir.join(&crate_name).join("XML" ); |
50 | |
51 | // If no XML path is provided, try to find the default XML path. |
52 | if xml.is_none() { |
53 | if current_dir_lower_case.exists() { |
54 | xml = Some( |
55 | current_dir_lower_case |
56 | .to_str() |
57 | .expect("current_dir_lower_case is valid UTF-8" ), |
58 | ); |
59 | } |
60 | |
61 | if current_dir_upper_case.exists() { |
62 | xml = Some( |
63 | current_dir_upper_case |
64 | .to_str() |
65 | .expect("current_dir_upper_case is valid UTF-8" ), |
66 | ); |
67 | } |
68 | |
69 | if parent_dir_lower_case.exists() { |
70 | xml = Some( |
71 | parent_dir_lower_case |
72 | .to_str() |
73 | .expect("parent_dir_lower_case is valid UTF-8" ), |
74 | ); |
75 | } |
76 | |
77 | if parent_dir_upper_case.exists() { |
78 | xml = Some( |
79 | parent_dir_upper_case |
80 | .to_str() |
81 | .expect("parent_dir_upper_case is valid UTF-8" ), |
82 | ); |
83 | } |
84 | |
85 | if crate_dir_lower_case.exists() { |
86 | xml = Some( |
87 | crate_dir_lower_case |
88 | .to_str() |
89 | .expect("crate_dir_lower_case is valid UTF-8" ), |
90 | ); |
91 | } |
92 | |
93 | if crate_dir_upper_case.exists() { |
94 | xml = Some( |
95 | crate_dir_upper_case |
96 | .to_str() |
97 | .expect("crate_dir_upper_case is valid UTF-8" ), |
98 | ); |
99 | } |
100 | } |
101 | |
102 | let env_xml_path = std::env::var("LOCKSTEP_XML_PATH" ); |
103 | if env_xml_path.is_ok() { |
104 | // Override the default, or argument path if the environment variable is set. |
105 | xml = env_xml_path.as_ref().map(|s| s.as_str()).ok(); |
106 | } |
107 | |
108 | // If no XML path is provided and the default XML path is not found, panic. |
109 | if xml.is_none() { |
110 | panic!( |
111 | "No XML path provided and default XML path not found. Current dir: \"{}\" " , |
112 | current_dir.to_str().expect("current_dir is valid UTF-8" ) |
113 | ); |
114 | } |
115 | |
116 | // Convert, canonicalize and return the XML path. |
117 | let xml = PathBuf::from_str(xml.unwrap())?; |
118 | Ok(xml.canonicalize()?) |
119 | } |
120 | |
121 | /// A generic helper to find the file path and interface name of a member. |
122 | #[doc (hidden)] |
123 | #[macro_export ] |
124 | macro_rules! find_definition_in_dbus_xml { |
125 | ($xml_path_buf:expr, $member:expr, $iface:expr, $msg_type:expr) => {{ |
126 | use $crate::MsgType; |
127 | |
128 | let xml_path_buf: std::path::PathBuf = $xml_path_buf; |
129 | let member: &str = $member; |
130 | let iface: Option<String> = $iface; |
131 | let msg_type: MsgType = $msg_type; |
132 | |
133 | let mut xml_file_path = None; |
134 | let mut interface_name = None; |
135 | |
136 | let read_dir = std::fs::read_dir(&xml_path_buf).expect("Failed to read XML directory" ); |
137 | |
138 | // Walk the XML files in the directory. |
139 | for entry in read_dir { |
140 | let entry = entry.expect("Failed to read entry" ); |
141 | |
142 | // Skip directories and non-XML files. |
143 | if entry.path().is_dir() || entry.path().extension().unwrap() != "xml" { |
144 | continue; |
145 | } |
146 | |
147 | let entry_path = entry.path().clone(); |
148 | let file = std::fs::File::open(entry.path()).expect("Failed to open file" ); |
149 | let node = $crate::zbus_xml::Node::from_reader(file).expect("Failed to parse XML file" ); |
150 | |
151 | for interface in node.interfaces() { |
152 | // If called with an `iface` arg, skip he interfaces that do not match. |
153 | if iface.is_some() && interface.name().as_str() != iface.clone().unwrap() { |
154 | continue; |
155 | } |
156 | |
157 | match msg_type { |
158 | MsgType::Method => { |
159 | for dbus_item in interface.methods() { |
160 | if dbus_item.name() == member { |
161 | if interface_name.is_some() { |
162 | panic!( |
163 | "Multiple interfaces offer the same {:?} member: {}, please specify the interface name." , |
164 | msg_type, member |
165 | ); |
166 | } |
167 | interface_name = Some(interface.name().to_string()); |
168 | xml_file_path = Some(entry_path.clone()); |
169 | continue; |
170 | } |
171 | } |
172 | } |
173 | MsgType::Signal => { |
174 | for dbus_item in interface.signals() { |
175 | if dbus_item.name() == member { |
176 | if interface_name.is_some() { |
177 | panic!( |
178 | "Multiple interfaces offer the same {:?} member: {}, please specify the interface name." , |
179 | msg_type, member |
180 | ); |
181 | } |
182 | interface_name = Some(interface.name().to_string()); |
183 | xml_file_path = Some(entry_path.clone()); |
184 | continue; |
185 | } |
186 | } |
187 | } |
188 | MsgType::Property => { |
189 | for dbus_item in interface.properties() { |
190 | if dbus_item.name() == member { |
191 | if interface_name.is_some() { |
192 | panic!( |
193 | "Multiple interfaces offer the same {:?} member: {}, please specify the interface name." , |
194 | msg_type, member |
195 | ); |
196 | } |
197 | interface_name = Some(interface.name().to_string()); |
198 | xml_file_path = Some(entry_path.clone()); |
199 | continue; |
200 | } |
201 | } |
202 | } |
203 | }; |
204 | } |
205 | } |
206 | |
207 | // If the interface member was not found, return an error. |
208 | 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 | /// Retrieve the signature of a method's return type. |
217 | /// |
218 | /// This macro will take a method member name and return the signature of the |
219 | /// return type. |
220 | /// |
221 | /// Essentially a wrapper around [`zbus_lockstep::get_method_return_type`], |
222 | /// but this macro tries to do its job with less arguments. |
223 | /// |
224 | /// It will search in the XML specification of the method for the return type |
225 | /// and return the signature of that type. |
226 | /// |
227 | /// If multiple interfaces offer the same method, you will need to specify the |
228 | /// interface name as well. |
229 | /// |
230 | /// This macro can be called with or without the interface name. |
231 | /// |
232 | /// # Examples |
233 | /// |
234 | /// Basic usage: |
235 | /// |
236 | /// ```rust |
237 | /// use zbus_lockstep::method_return_signature; |
238 | /// use zvariant::Signature; |
239 | /// |
240 | /// std::env::set_var("LOCKSTEP_XML_PATH" , "../xml" ); |
241 | /// |
242 | /// let sig = method_return_signature!("RequestName" ); |
243 | /// assert_eq!(&sig, &Signature::from_str_unchecked("u" )); |
244 | /// ``` |
245 | /// The macro supports colling arguments with identifiers as well as without. |
246 | /// The macro may also be called with an interface name or interface and argument name: |
247 | /// |
248 | /// ```rust |
249 | /// # use zbus_lockstep::{method_return_signature}; |
250 | /// # std::env::set_var("LOCKSTEP_XML_PATH" , "../xml" ); |
251 | /// let _sig = method_return_signature!("RequestName" , "org.example.Node" , "grape" ); |
252 | /// |
253 | /// // or alternatively |
254 | /// |
255 | /// let _sig = method_return_signature!(member: "RequestName" , interface: "org.example.Node" , argument: "grape" ); |
256 | /// ``` |
257 | #[macro_export ] |
258 | macro_rules! method_return_signature { |
259 | ($member:expr) => {{ |
260 | use $crate::MsgType; |
261 | let member = $member; |
262 | |
263 | // Looking for default path or path specified by environment variable. |
264 | let current_dir: std::path::PathBuf = std::env::current_dir().unwrap(); |
265 | let xml_path = $crate::resolve_xml_path(None).expect(&format!( |
266 | "Failed to resolve XML path, current dir: {}" , |
267 | current_dir.to_str().unwrap() |
268 | )); |
269 | |
270 | // Find the definition of the method in the XML specification. |
271 | let (file_path, interface_name) = |
272 | $crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Method); |
273 | |
274 | let file = std::fs::File::open(file_path).expect("Failed to open file" ); |
275 | $crate::get_method_return_type(file, &interface_name, member, None) |
276 | .expect("Failed to get method arguments type signature" ) |
277 | }}; |
278 | |
279 | (member: $member:expr) => { |
280 | $crate::method_return_signature!($member) |
281 | }; |
282 | |
283 | ($member:expr, $interface:expr) => {{ |
284 | let member = $member; |
285 | use $crate::MsgType; |
286 | |
287 | let interface = Some($interface.to_string()); |
288 | |
289 | // Looking for default path or path specified by environment variable. |
290 | let current_dir: std::path::PathBuf = std::env::current_dir().unwrap(); |
291 | let xml_path = $crate::resolve_xml_path(None).expect(&format!( |
292 | "Failed to resolve XML path, current dir: {}" , |
293 | current_dir.to_str().unwrap() |
294 | )); |
295 | |
296 | // Find the definition of the method in the XML specification. |
297 | let (file_path, interface_name) = |
298 | $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method); |
299 | |
300 | let file = std::fs::File::open(file_path).expect("Failed to open file" ); |
301 | $crate::get_method_return_type(file, &interface_name, member, None) |
302 | .expect("Failed to get method arguments type signature" ) |
303 | }}; |
304 | |
305 | (member: $member:expr, interface: $interface:expr) => { |
306 | $crate::method_return_signature!($member, $interface) |
307 | }; |
308 | |
309 | ($member:expr, $interface:expr, $argument:expr) => {{ |
310 | let member = $member; |
311 | use $crate::MsgType; |
312 | |
313 | let interface = Some($interface.to_string()); |
314 | let argument = Some($argument); |
315 | |
316 | // Looking for default path or path specified by environment variable. |
317 | let current_dir: std::path::PathBuf = std::env::current_dir().unwrap(); |
318 | let xml_path = $crate::resolve_xml_path(None).expect(&format!( |
319 | "Failed to resolve XML path, current dir: {}" , |
320 | current_dir.to_str().unwrap() |
321 | )); |
322 | |
323 | // Find the definition of the method in the XML specification. |
324 | let (file_path, interface_name) = |
325 | $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method); |
326 | |
327 | let file = std::fs::File::open(file_path).expect("Failed to open file" ); |
328 | $crate::get_method_return_type(file, &interface_name, member, argument) |
329 | .expect("Failed to get method argument(s) type signature" ) |
330 | }}; |
331 | |
332 | (member: $member:expr, interface: $interface:expr, argument: $argument:expr) => { |
333 | $crate::method_return_signature!($member, $interface, $argument) |
334 | }; |
335 | } |
336 | |
337 | /// Retrieve the signature of a method's arguments. |
338 | /// |
339 | /// Essentially a wrapper around [`zbus_lockstep::get_method_args_type`], |
340 | /// but this macro tries to do its job with less arguments. |
341 | /// |
342 | /// This macro will take a method member name and return the signature of the |
343 | /// arguments type. |
344 | /// |
345 | /// It will search in the XML specification of the method for the arguments type |
346 | /// and return the signature of that type. |
347 | /// |
348 | /// If multiple interfaces offer the same member, you will need to |
349 | /// specify the interface name as well. |
350 | /// |
351 | /// This macro can be called with or without the interface name. |
352 | /// |
353 | /// # Examples |
354 | /// |
355 | /// ```rust |
356 | /// use zbus_lockstep::method_args_signature; |
357 | /// use zvariant::Signature; |
358 | /// |
359 | /// std::env::set_var("LOCKSTEP_XML_PATH" , "../xml" ); |
360 | /// |
361 | /// let sig = method_args_signature!("RequestName" ); |
362 | /// assert_eq!(&sig, &Signature::from_str_unchecked("(su)" )); |
363 | /// ``` |
364 | /// The macro supports colling arguments with identifiers as well as without. |
365 | /// The macro may also be called with an interface name or interface and argument name: |
366 | /// |
367 | /// ```rust |
368 | /// # use zbus_lockstep::{method_args_signature}; |
369 | /// # std::env::set_var("LOCKSTEP_XML_PATH" , "../xml" ); |
370 | /// let _sig = method_args_signature!("RequestName" , "org.example.Node" , "apple" ); |
371 | /// |
372 | /// // or alternatively |
373 | /// |
374 | /// let _sig = method_args_signature!(member: "RequestName" , interface: "org.example.Node" , argument: "apple" ); |
375 | /// ``` |
376 | #[macro_export ] |
377 | macro_rules! method_args_signature { |
378 | ($member:expr) => {{ |
379 | use $crate::MsgType; |
380 | let member = $member; |
381 | |
382 | // Looking for default path or path specified by environment variable. |
383 | let current_dir: std::path::PathBuf = std::env::current_dir().unwrap(); |
384 | let xml_path = $crate::resolve_xml_path(None).expect(&format!( |
385 | "Failed to resolve XML path, current dir: {}" , |
386 | current_dir.to_str().unwrap() |
387 | )); |
388 | |
389 | // Find the definition of the method in the XML specification. |
390 | let (file_path, interface_name) = |
391 | $crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Method); |
392 | |
393 | let file = std::fs::File::open(file_path).expect("Failed to open file" ); |
394 | $crate::get_method_args_type(file, &interface_name, member, None) |
395 | .expect("Failed to get method arguments type signature" ) |
396 | }}; |
397 | |
398 | (member: $member:expr) => { |
399 | $crate::method_args_signature!($member) |
400 | }; |
401 | |
402 | ($member:expr, $interface:expr) => {{ |
403 | use $crate::MsgType; |
404 | let member = $member; |
405 | |
406 | let interface = Some($interface.to_string()); |
407 | |
408 | // Looking for default path or path specified by environment variable. |
409 | let current_dir: std::path::PathBuf = std::env::current_dir().unwrap(); |
410 | let xml_path = $crate::resolve_xml_path(None).expect(&format!( |
411 | "Failed to resolve XML path, current dir: {}" , |
412 | current_dir.to_str().unwrap() |
413 | )); |
414 | |
415 | // Find the definition of the method in the XML specification. |
416 | let (file_path, interface_name) = |
417 | $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method); |
418 | |
419 | let file = std::fs::File::open(file_path).expect("Failed to open file" ); |
420 | $crate::get_method_args_type(file, &interface_name, member, None) |
421 | .expect("Failed to get method arguments type signature" ) |
422 | }}; |
423 | |
424 | (member: $member:expr, interface: $interface:expr) => { |
425 | $crate::method_args_signature!($member, $interface) |
426 | }; |
427 | |
428 | ($member:expr, $interface:expr, $argument:expr) => {{ |
429 | use $crate::MsgType; |
430 | let member = $member; |
431 | let interface = Some($interface.to_string()); |
432 | |
433 | let argument = Some($argument); |
434 | |
435 | // Looking for default path or path specified by environment variable. |
436 | let current_dir: std::path::PathBuf = std::env::current_dir().unwrap(); |
437 | |
438 | let xml_path = $crate::resolve_xml_path(None).expect(&format!( |
439 | "Failed to resolve XML path, current dir: {}" , |
440 | current_dir.to_str().unwrap() |
441 | )); |
442 | // Find the definition of the method in the XML specification. |
443 | let (file_path, interface_name) = |
444 | $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Method); |
445 | |
446 | let file = std::fs::File::open(file_path).expect("Failed to open file" ); |
447 | $crate::get_method_args_type(file, &interface_name, member, argument) |
448 | .expect("Failed to get method argument(s) type signature" ) |
449 | }}; |
450 | |
451 | (member: $member:expr, interface: $interface:expr, argument: $argument:expr) => { |
452 | $crate::method_args_signature!($member, $interface, $argument) |
453 | }; |
454 | } |
455 | |
456 | /// Retrieve the signature of a signal's body type. |
457 | /// |
458 | /// Essentially a wrapper around [`zbus_lockstep::get_signal_body_type`], |
459 | /// but this macro tries to find it with less arguments. |
460 | /// |
461 | /// This macro will take a signal member name and return the signature of the |
462 | /// signal body type. |
463 | /// |
464 | /// If multiple interfaces offer the same member, you will need to |
465 | /// specify the interface name as well. |
466 | /// |
467 | /// This macro can be called with or without the interface name. |
468 | /// |
469 | /// # Examples |
470 | /// |
471 | /// ```rust |
472 | /// use zbus_lockstep::signal_body_type_signature; |
473 | /// use zvariant::Signature; |
474 | /// |
475 | /// std::env::set_var("LOCKSTEP_XML_PATH" , "../xml" ); |
476 | /// |
477 | /// let sig = signal_body_type_signature!("AddNode" ); |
478 | /// assert_eq!(&sig, &Signature::from_str_unchecked("(so)" )); |
479 | /// ``` |
480 | /// The macro supports colling arguments with identifiers as well as without. |
481 | /// The macro may also be called with an interface name or interface and argument name: |
482 | /// |
483 | /// ```rust |
484 | /// # use zbus_lockstep::{signal_body_type_signature}; |
485 | /// # std::env::set_var("LOCKSTEP_XML_PATH" , "../xml" ); |
486 | /// let _sig = signal_body_type_signature!("Alert" , "org.example.Node" , "color" ); |
487 | /// |
488 | /// // or alternatively |
489 | /// |
490 | /// let _sig = signal_body_type_signature!(member: "Alert" , interface: "org.example.Node" , argument: "color" ); |
491 | /// ``` |
492 | #[macro_export ] |
493 | macro_rules! signal_body_type_signature { |
494 | ($member:expr) => {{ |
495 | use $crate::MsgType; |
496 | let member = $member; |
497 | |
498 | // Looking for default path or path specified by environment variable. |
499 | let current_dir: std::path::PathBuf = std::env::current_dir().unwrap(); |
500 | let xml_path = $crate::resolve_xml_path(None).expect(&format!( |
501 | "Failed to resolve XML path, current dir: {}" , |
502 | current_dir.to_str().unwrap() |
503 | )); |
504 | |
505 | // Find the definition of the method in the XML specification. |
506 | let (file_path, interface_name) = |
507 | $crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Signal); |
508 | |
509 | let file = std::fs::File::open(file_path).expect("Failed to open file" ); |
510 | |
511 | $crate::get_signal_body_type(file, &interface_name, member, None) |
512 | .expect("Failed to get method arguments type signature" ) |
513 | }}; |
514 | |
515 | (member: $member:expr) => { |
516 | $crate::signal_body_type_signature!($member) |
517 | }; |
518 | |
519 | ($member:expr, $interface:expr) => {{ |
520 | use $crate::MsgType; |
521 | let member = $member; |
522 | let interface = Some($interface.to_string()); |
523 | |
524 | // Looking for default path or path specified by environment variable. |
525 | let current_dir: std::path::PathBuf = std::env::current_dir().unwrap(); |
526 | let xml_path = $crate::resolve_xml_path(None).expect(&format!( |
527 | "Failed to resolve XML path, current dir: {}" , |
528 | current_dir.to_str().unwrap() |
529 | )); |
530 | |
531 | // Find the definition of the method in the XML specification. |
532 | let (file_path, interface_name) = |
533 | $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Signal); |
534 | |
535 | let file = std::fs::File::open(file_path).expect("Failed to open file" ); |
536 | $crate::get_signal_body_type(file, &interface_name, member, None) |
537 | .expect("Failed to get method arguments type signature" ) |
538 | }}; |
539 | |
540 | (member: $member:expr, interface: $interface:expr) => { |
541 | $crate::signal_body_type_signature!($member, $interface) |
542 | }; |
543 | |
544 | ($member:expr, $interface:expr, $argument:expr) => {{ |
545 | use $crate::MsgType; |
546 | let member = $member; |
547 | let interface = Some($interface.to_string()); |
548 | |
549 | let argument = Some($argument); |
550 | |
551 | // Looking for default path or path specified by environment variable. |
552 | let current_dir: std::path::PathBuf = std::env::current_dir().unwrap(); |
553 | |
554 | let xml_path = $crate::resolve_xml_path(None).expect(&format!( |
555 | "Failed to resolve XML path, current dir: {}" , |
556 | current_dir.to_str().unwrap() |
557 | )); |
558 | |
559 | // Find the definition of the method in the XML specification. |
560 | let (file_path, interface_name) = |
561 | $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Signal); |
562 | |
563 | let file = std::fs::File::open(file_path).expect("Failed to open file" ); |
564 | $crate::get_signal_body_type(file, &interface_name, member, argument) |
565 | .expect("Failed to get method argument(s) type signature" ) |
566 | }}; |
567 | |
568 | (member: $member:expr, interface: $interface:expr, argument: $argument:expr) => { |
569 | $crate::signal_body_type_signature!($member, $interface, $argument) |
570 | }; |
571 | } |
572 | |
573 | /// Retrieve the signature of a property's type. |
574 | /// |
575 | /// Essentially a wrapper around [`zbus_lockstep::get_property_type`], |
576 | /// but this macro tries to do with less arguments. |
577 | /// |
578 | /// This macro will take a property name and return the signature of the |
579 | /// property's type. |
580 | /// |
581 | /// If multiple interfaces offer the same member, you will need to |
582 | /// specify the interface name as well. |
583 | /// |
584 | /// This macro can be called with or without the interface name. |
585 | /// |
586 | /// # Examples |
587 | /// |
588 | /// ```rust |
589 | /// use zbus_lockstep::property_type_signature; |
590 | /// use zvariant::Signature; |
591 | /// |
592 | /// std::env::set_var("LOCKSTEP_XML_PATH" , "../xml" ); |
593 | /// |
594 | /// let sig = property_type_signature!("Features" ); |
595 | /// assert_eq!(&sig, &Signature::from_str_unchecked("as" )); |
596 | /// ``` |
597 | /// The member name and/or interface name can be used tp identify the arguments: |
598 | /// |
599 | /// ```rust |
600 | /// # use zbus_lockstep::{property_type_signature}; |
601 | /// # std::env::set_var("LOCKSTEP_XML_PATH" , "../xml" ); |
602 | /// let _sig = property_type_signature!(member: "Features" , interface: "org.example.Node" ); |
603 | /// ``` |
604 | #[macro_export ] |
605 | macro_rules! property_type_signature { |
606 | ($member:expr) => {{ |
607 | use $crate::MsgType; |
608 | let member = $member; |
609 | |
610 | // Looking for default path or path specified by environment variable. |
611 | let current_dir: std::path::PathBuf = std::env::current_dir().unwrap(); |
612 | let xml_path = $crate::resolve_xml_path(None).expect(&format!( |
613 | "Failed to resolve XML path, current dir: {}" , |
614 | current_dir.to_str().unwrap() |
615 | )); |
616 | |
617 | // Find the definition of the method in the XML specification. |
618 | let (file_path, interface_name) = |
619 | $crate::find_definition_in_dbus_xml!(xml_path, member, None, MsgType::Property); |
620 | |
621 | let file = std::fs::File::open(file_path).expect("Failed to open file" ); |
622 | |
623 | $crate::get_property_type(file, &interface_name, member) |
624 | .expect("Failed to get property type signature" ) |
625 | }}; |
626 | |
627 | (member: $member:expr) => { |
628 | $crate::property_type_signature!($member) |
629 | }; |
630 | |
631 | ($member:expr, $interface:expr) => {{ |
632 | use $crate::MsgType; |
633 | let member = $member; |
634 | let interface = Some($interface.to_string()); |
635 | |
636 | // Looking for default path or path specified by environment variable. |
637 | let current_dir: std::path::PathBuf = std::env::current_dir().unwrap(); |
638 | let xml_path = $crate::resolve_xml_path(None).expect(&format!( |
639 | "Failed to resolve XML path, current dir: {}" , |
640 | current_dir.to_str().unwrap() |
641 | )); |
642 | |
643 | // Find the definition of the method in the XML specification. |
644 | let (file_path, interface_name) = |
645 | $crate::find_definition_in_dbus_xml!(xml_path, member, interface, MsgType::Property); |
646 | |
647 | let file = std::fs::File::open(file_path).expect("Failed to open file" ); |
648 | $crate::get_property_type(file, &interface_name, member) |
649 | .expect("Failed to get property type signature" ) |
650 | }}; |
651 | |
652 | (member: $member:expr, interface: $interface:expr) => { |
653 | $crate::property_type_signature!($member, $interface) |
654 | }; |
655 | } |
656 | |
657 | #[cfg (test)] |
658 | mod test { |
659 | use zvariant::Signature; |
660 | |
661 | use crate::signal_body_type_signature; |
662 | |
663 | #[test ] |
664 | fn test_signal_body_signature_macro() { |
665 | // path to XML files can be set by environment variable |
666 | // std::env::set_var("LOCKSTEP_XML_PATH", "../xml"); |
667 | // But `resolve_xml_path` can find the `xml` in parent by itself. |
668 | |
669 | let sig = crate::signal_body_type_signature!("AddNode" ); |
670 | assert_eq!(&sig, &zvariant::Signature::from_str_unchecked("(so)" )); |
671 | } |
672 | |
673 | #[test ] |
674 | fn test_signal_body_signature_macro_with_identifier() { |
675 | let sig = crate::signal_body_type_signature!(member: "AddNode" ); |
676 | assert_eq!(sig, Signature::from_str_unchecked("(so)" )); |
677 | } |
678 | |
679 | #[test ] |
680 | fn test_signal_body_signature_macro_with_interface() { |
681 | let sig = crate::signal_body_type_signature!("AddNode" , "org.example.Node" ); |
682 | assert_eq!(sig, Signature::from_str_unchecked("(so)" )); |
683 | } |
684 | |
685 | #[test ] |
686 | fn test_signal_body_signature_macro_with_interface_and_identifiers() { |
687 | let sig = |
688 | crate::signal_body_type_signature!(member: "AddNode" , interface: "org.example.Node" ); |
689 | assert_eq!(sig, Signature::from_str_unchecked("(so)" )); |
690 | } |
691 | |
692 | #[test ] |
693 | fn test_signal_body_signature_macro_with_argument_and_interface() { |
694 | let sig = crate::signal_body_type_signature!("Alert" , "org.example.Node" , "volume" ); |
695 | assert_eq!(sig, Signature::from_str_unchecked("d" )); |
696 | } |
697 | |
698 | #[test ] |
699 | fn test_signal_body_signature_macro_with_argument_and_identifiers_and_interface() { |
700 | let sig = crate::signal_body_type_signature!( |
701 | member: "Alert" , |
702 | interface: "org.example.Node" , |
703 | argument: "urgent" |
704 | ); |
705 | assert_eq!(sig, Signature::from_str_unchecked("b" )); |
706 | } |
707 | |
708 | #[test ] |
709 | fn test_method_args_signature_macro() { |
710 | let sig = crate::method_args_signature!("RequestName" ); |
711 | assert_eq!(sig, Signature::from_str_unchecked("(su)" )); |
712 | } |
713 | |
714 | #[test ] |
715 | fn test_method_args_signature_macro_with_identifier() { |
716 | let sig = crate::method_args_signature!(member: "RequestName" ); |
717 | assert_eq!(sig, Signature::from_str_unchecked("(su)" )); |
718 | } |
719 | |
720 | #[test ] |
721 | fn test_method_args_signature_macro_with_interface() { |
722 | let sig = crate::method_args_signature!("RequestName" , "org.example.Node" ); |
723 | assert_eq!(sig, Signature::from_str_unchecked("(su)" )); |
724 | } |
725 | |
726 | #[test ] |
727 | fn test_method_args_signature_macro_with_interface_and_identifiers() { |
728 | let sig = |
729 | crate::method_args_signature!(member: "RequestName" , interface: "org.example.Node" ); |
730 | assert_eq!(sig, Signature::from_str_unchecked("(su)" )); |
731 | } |
732 | |
733 | #[test ] |
734 | fn test_method_args_signature_macro_with_argument_and_interface() { |
735 | let sig = crate::method_args_signature!("RequestName" , "org.example.Node" , "apple" ); |
736 | assert_eq!(sig, Signature::from_str_unchecked("s" )); |
737 | } |
738 | |
739 | #[test ] |
740 | fn test_method_args_signature_macro_with_argument_and_identifiers_and_interface() { |
741 | let sig = crate::method_args_signature!( |
742 | member: "RequestName" , |
743 | interface: "org.example.Node" , |
744 | argument: "orange" |
745 | ); |
746 | assert_eq!(sig, Signature::from_str_unchecked("u" )); |
747 | } |
748 | |
749 | #[test ] |
750 | fn test_method_return_signature_macro() { |
751 | let sig = crate::method_return_signature!("RequestName" ); |
752 | assert_eq!(sig, Signature::from_str_unchecked("u" )); |
753 | } |
754 | |
755 | #[test ] |
756 | fn test_method_return_signature_macro_with_identifier() { |
757 | let sig = crate::method_return_signature!(member: "RequestName" ); |
758 | assert_eq!(sig, Signature::from_str_unchecked("u" )); |
759 | } |
760 | |
761 | #[test ] |
762 | fn test_method_return_signature_macro_with_interface() { |
763 | let sig = crate::method_return_signature!("RequestName" , "org.example.Node" ); |
764 | assert_eq!(sig, Signature::from_str_unchecked("u" )); |
765 | } |
766 | |
767 | #[test ] |
768 | fn test_method_return_signature_macro_with_interface_and_identifiers() { |
769 | let sig = |
770 | crate::method_return_signature!(member: "RequestName" , interface: "org.example.Node" ); |
771 | assert_eq!(sig, Signature::from_str_unchecked("u" )); |
772 | } |
773 | |
774 | #[test ] |
775 | fn test_method_return_signature_macro_with_argument_and_interface() { |
776 | let sig = crate::method_return_signature!("RequestName" , "org.example.Node" , "grape" ); |
777 | assert_eq!(sig, Signature::from_str_unchecked("u" )); |
778 | } |
779 | |
780 | #[test ] |
781 | fn test_method_return_signature_macro_with_argument_and_identifiers_and_interface() { |
782 | let sig = crate::method_return_signature!( |
783 | member: "RequestName" , |
784 | interface: "org.example.Node" , |
785 | argument: "grape" |
786 | ); |
787 | assert_eq!(sig, Signature::from_str_unchecked("u" )); |
788 | } |
789 | |
790 | #[test ] |
791 | fn test_property_type_signature_macro() { |
792 | let sig = crate::property_type_signature!("Features" ); |
793 | assert_eq!(sig, Signature::from_str_unchecked("as" )); |
794 | } |
795 | |
796 | #[test ] |
797 | fn test_property_type_signature_macro_with_identifier() { |
798 | let sig = crate::property_type_signature!(member: "Features" ); |
799 | assert_eq!(sig, Signature::from_str_unchecked("as" )); |
800 | } |
801 | |
802 | #[test ] |
803 | fn test_property_type_signature_macro_with_interface() { |
804 | let sig = crate::property_type_signature!("Features" , "org.example.Node" ); |
805 | assert_eq!(sig, Signature::from_str_unchecked("as" )); |
806 | } |
807 | |
808 | #[test ] |
809 | fn test_property_type_signature_macro_with_interface_and_identifiers() { |
810 | let sig = |
811 | crate::property_type_signature!(member: "Features" , interface: "org.example.Node" ); |
812 | assert_eq!(sig, Signature::from_str_unchecked("as" )); |
813 | } |
814 | } |
815 | |