1/// Expands to implement the required methods for the [`crate::EventProperties`] trait.
2/// This depends on the struct to have an `item` field of type `ObjectRef`.
3///
4/// ```ignore
5/// impl_from_interface_event_enum_for_event!(TextCaretMovedEvent);
6/// ```
7///
8/// Expands to:
9///
10/// ```ignore
11/// impl EventProperties for TextCaretMovedEvent {
12/// fn sender(&self) -> UniqueName<'_> {
13/// self.item.name.as_ref()
14/// }
15/// fn path(&self) -> ObjectPath<'_> {
16/// self.item.path.as_ref()
17/// }
18/// }
19/// ```
20macro_rules! impl_event_properties {
21 ($type:ty) => {
22 impl EventProperties for $type {
23 fn sender(&self) -> UniqueName<'_> {
24 self.item.name.as_ref()
25 }
26 fn path(&self) -> ObjectPath<'_> {
27 self.item.path.as_ref()
28 }
29 }
30 };
31}
32
33/// Expands to a conversion given the enclosed event type and outer `Event` variant.
34///
35/// eg
36/// ```ignore
37/// impl_from_interface_event_enum_for_event!(ObjectEvents, Event::Object);
38/// ```
39/// expands to:
40///
41/// ```ignore
42/// impl From<ObjectEvents> for Event {
43/// fn from(event_variant: ObjectEvents) -> Event {
44/// Event::Object(event_variant.into())
45/// }
46/// }
47/// ```
48macro_rules! impl_from_interface_event_enum_for_event {
49 ($outer_type:ty, $outer_variant:path) => {
50 impl From<$outer_type> for Event {
51 fn from(event_variant: $outer_type) -> Event {
52 $outer_variant(event_variant.into())
53 }
54 }
55 };
56}
57
58/// Expands to a conversion given the enclosed event enum type and outer `Event` variant.
59///
60/// eg
61/// ```ignore
62/// impl_try_from_event_for_user_facing_event_type!(ObjectEvents, Event::Object);
63/// ```
64/// expands to:
65///
66/// ```ignore
67/// impl TryFrom<Event> for ObjectEvents {
68/// type Error = AtspiError;
69/// fn try_from(generic_event: Event) -> Result<ObjectEvents, Self::Error> {
70/// if let Event::Object(event_type) = generic_event {
71/// Ok(event_type)
72/// } else {
73/// Err(AtspiError::Conversion("Invalid type"))
74/// }
75/// }
76/// }
77/// ```
78macro_rules! impl_try_from_event_for_user_facing_event_type {
79 ($outer_type:ty, $outer_variant:path) => {
80 impl TryFrom<Event> for $outer_type {
81 type Error = AtspiError;
82 fn try_from(generic_event: Event) -> Result<$outer_type, Self::Error> {
83 if let $outer_variant(event_type) = generic_event {
84 Ok(event_type)
85 } else {
86 Err(AtspiError::Conversion("Invalid type"))
87 }
88 }
89 }
90 };
91}
92
93/// Expands to a conversion given the user facing event type and outer `Event::Interface(<InterfaceEnum>)` variant.,
94/// the enum type and outtermost variant.
95///
96/// ```ignore user facing type, enum type, outer variant
97/// impl_from_user_facing_event_for_interface_event_enum!(StateChangedEvent, ObjectEvents, ObjectEvents::StateChanged);
98/// ```
99///
100/// expands to:
101///
102/// ```ignore
103/// impl From<StateChangedEvent> for ObjectEvents {
104/// fn from(specific_event: StateChangedEvent) -> ObjectEvents {
105/// ObjectEvents::StateChanged(specific_event)
106/// }
107/// }
108/// ```
109macro_rules! impl_from_user_facing_event_for_interface_event_enum {
110 ($inner_type:ty, $outer_type:ty, $inner_variant:path) => {
111 impl From<$inner_type> for $outer_type {
112 fn from(specific_event: $inner_type) -> $outer_type {
113 $inner_variant(specific_event)
114 }
115 }
116 };
117}
118
119/// Expands to a conversion given two arguments,
120/// 1. the user facing event type `(inner_type)`
121/// which relies on a conversion to its interface variant enum type variant.
122/// 2. the outer `Event::<Interface(<InterfaceEnum>)>` wrapper.,
123/// the enum type and outtermost variant.
124///
125/// ```ignore user facing type, outer event variant
126/// impl_from_user_facing_type_for_event_enum!(StateChangedEvent, Event::Object);
127/// ```
128///
129/// expands to:
130///
131/// ```ignore
132/// impl From<StateChangedEvent> for Event {
133/// fn from(event_variant: StateChangedEvent) -> Event {
134/// Event::Object(ObjectEvents::StateChanged(event_variant))
135/// }
136/// }
137/// ```
138macro_rules! impl_from_user_facing_type_for_event_enum {
139 ($inner_type:ty, $outer_variant:path) => {
140 impl From<$inner_type> for Event {
141 fn from(event_variant: $inner_type) -> Event {
142 $outer_variant(event_variant.into())
143 }
144 }
145 };
146}
147
148/// Expands to a conversion given two arguments,
149/// 1. the user facing event type `(inner_type)`
150/// 2. the outer `Event::<Interface(<InterfaceEnum>)>` wrapper.
151///
152/// eg
153/// ```ignore
154/// impl_try_from_event_for_user_facing_type!(StateChangedEvent, ObjectEvents::StateChanged);
155/// ```
156/// expands to:
157///
158/// ```ignore
159/// impl TryFrom<Event> for StateChangedEvent {
160/// type Error = AtspiError;
161/// fn try_from(generic_event: Event) -> Result<StateChangedEvent, Self::Error> {
162/// if let Event::Object(ObjectEvents::StateChanged(specific_event)) = generic_event {
163/// Ok(specific_event)
164/// } else {
165/// Err(AtspiError::Conversion("Invalid type"))
166/// }
167/// }
168/// }
169/// ```
170macro_rules! impl_try_from_event_for_user_facing_type {
171 ($inner_type:ty, $inner_variant:path, $outer_variant:path) => {
172 impl TryFrom<Event> for $inner_type {
173 type Error = AtspiError;
174 fn try_from(generic_event: Event) -> Result<$inner_type, Self::Error> {
175 if let $outer_variant($inner_variant(specific_event)) = generic_event {
176 Ok(specific_event)
177 } else {
178 Err(AtspiError::Conversion("Invalid type"))
179 }
180 }
181 }
182 };
183}
184
185/// Implements the `TryFrom` trait for a given event type.
186/// Converts a user facing event type into a `zbus::Message`.
187///
188/// # Example
189/// ```ignore
190/// impl_to_dbus_message!(StateChangedEvent);
191/// ```
192/// expands to:
193///
194/// ```ignore
195/// impl TryFrom<StateChangedEvent> for zbus::Message {
196/// type Error = AtspiError;
197/// fn try_from(event: StateChangedEvent) -> Result<Self, Self::Error> {
198/// Ok(zbus::Message::signal(
199/// event.path(),
200/// StateChangedEvent::DBUS_INTERFACE,
201/// StateChangedEvent::DBUS_MEMBER,
202/// )?
203/// .sender(event.sender())?
204/// .build(&event.body())?)
205/// }
206/// }
207///
208macro_rules! impl_to_dbus_message {
209 ($type:ty) => {
210 #[cfg(feature = "zbus")]
211 impl TryFrom<$type> for zbus::Message {
212 type Error = AtspiError;
213 fn try_from(event: $type) -> Result<Self, Self::Error> {
214 Ok(zbus::Message::signal(
215 event.path(),
216 <$type as BusProperties>::DBUS_INTERFACE,
217 <$type as BusProperties>::DBUS_MEMBER,
218 )?
219 .sender(event.sender().to_string())?
220 .build(&event.body())?)
221 }
222 }
223 };
224}
225
226/// Implements the `TryFrom` trait for a given event type.
227/// Converts a `zbus::Message` into a user facing event type.
228///
229/// # Example
230/// ```ignore
231/// impl_from_dbus_message!(StateChangedEvent);
232/// ```
233/// expands to:
234///
235/// ```ignore
236/// impl TryFrom<&zbus::Message> for StateChangedEvent {
237/// type Error = AtspiError;
238/// fn try_from(msg: &zbus::Message) -> Result<Self, Self::Error> {
239/// if msg.header().interface().ok_or(AtspiError::MissingInterface)? != StateChangedEvent::DBUS_INTERFACE {
240/// return Err(AtspiError::InterfaceMatch(format!("The interface {} does not match the signal's interface: {}",
241/// msg.header().interface().unwrap(),
242/// StateChangedEvent::DBUS_INTERFACE)));
243/// }
244/// if msg.header().member().ok_or(AtspiError::MissingMember)? != StateChangedEvent::DBUS_MEMBER {
245/// return Err(AtspiError::MemberMatch(format!("The member {} does not match the signal's member: {}",
246/// msg.header().member().unwrap(),
247/// StateChangedEvent::DBUS_MEMBER)));
248/// }
249/// StateChangedEvent::from_message_parts(msg.try_into()?, msg.body().deserialize::<StateChangedEvent::Body>()?)
250/// }
251/// }
252/// ```
253macro_rules! impl_from_dbus_message {
254 ($type:ty) => {
255 #[cfg(feature = "zbus")]
256 impl TryFrom<&zbus::Message> for $type {
257 type Error = AtspiError;
258 fn try_from(msg: &zbus::Message) -> Result<Self, Self::Error> {
259 let header = msg.header();
260 if header.interface().ok_or(AtspiError::MissingInterface)?
261 != <$type as BusProperties>::DBUS_INTERFACE
262 {
263 return Err(AtspiError::InterfaceMatch(format!(
264 "The interface {} does not match the signal's interface: {}",
265 header.interface().unwrap(),
266 <$type as BusProperties>::DBUS_INTERFACE
267 )));
268 }
269 if header.member().ok_or(AtspiError::MissingMember)? != <$type>::DBUS_MEMBER {
270 return Err(AtspiError::MemberMatch(format!(
271 "The member {} does not match the signal's member: {}",
272 // unwrap is safe here because of guard above
273 header.member().unwrap(),
274 <$type as BusProperties>::DBUS_MEMBER
275 )));
276 }
277 <$type>::from_message_parts(
278 msg.try_into()?,
279 msg.body().deserialize::<<$type as BusProperties>::Body>()?,
280 )
281 }
282 }
283 };
284}
285
286// We decorate the macro with a `#[cfg(test)]` attribute.
287// This prevents Clippy from complaining about the macro not being used.
288// It is being used, but only in test mode.
289//
290/// Tests `Default` and `BusProperties::from_message_parts` for a given event struct.
291///
292/// Obtains a default for the given event struct.
293/// Asserts that the path and sender are the default.
294///
295/// Breaks the struct down into item (the associated object) and body.
296/// Then tests `BusProperties::from_message_parts` with the item and body.
297#[cfg(test)]
298macro_rules! generic_event_test_case {
299 ($type:ty) => {
300 #[test]
301 fn generic_event_uses() {
302 let struct_event = <$type>::default();
303 assert_eq!(struct_event.path().as_str(), "/org/a11y/atspi/accessible/null");
304 assert_eq!(struct_event.sender().as_str(), ":0.0");
305 let item = struct_event.item.clone();
306 let body = struct_event.body();
307 let build_struct = <$type>::from_message_parts(item, body)
308 .expect("<$type as Default>'s parts should build a valid ObjectRef");
309 assert_eq!(struct_event, build_struct);
310 }
311 };
312}
313
314// We decorate the macro with a `#[cfg(test)]` attribute.
315// This prevents Clippy from complaining about the macro not being used.
316// It is being used, but only in test mode.
317//
318/// Tests conversion to and from the `Event` enum.
319///
320/// Obtains a default for the given event struct.
321/// Converts the struct into the `Event` enum, wrapping the struct.
322/// Converts the `Event` enum into the given event struct.
323/// Asserts that the original struct and the converted struct are equal.
324#[cfg(test)]
325macro_rules! event_enum_test_case {
326 ($type:ty) => {
327 #[test]
328 fn event_enum_conversion() {
329 let struct_event = <$type>::default();
330 let event = Event::from(struct_event.clone());
331 let struct_event_back = <$type>::try_from(event)
332 .expect("Should convert event enum into specific event type because it was created from it. Check the `impl_from_interface_event_enum_for_event` macro");
333 assert_eq!(struct_event, struct_event_back);
334 }
335 };
336}
337
338/// Tests transparency of the `EventTypeProperties` and `EventProperties` trait on the `Event` wrapper type.
339///
340/// Obtains a default for the given event struct.
341/// Converts the struct into the `Event` enum, wrapping the struct.
342/// Checks the equality of all four functions defined in the `EventTypeProiperties` and `EventProperties` traits:
343///
344/// - `member`
345/// - `interface`
346/// - `registry_string`
347/// - `match_rule`
348/// - `path`
349/// - `sender`
350///
351/// It is imperitive that these items come through with no modifications from the wrappers.
352///
353#[cfg(test)]
354macro_rules! event_enum_transparency_test_case {
355 ($type:ty) => {
356 #[test]
357 fn event_enum_transparency_test_case() {
358 let specific_event = <$type>::default();
359 let generic_event = Event::from(specific_event.clone());
360 assert_eq!(
361 specific_event.member(),
362 generic_event.member(),
363 "DBus member strings do not match."
364 );
365 assert_eq!(
366 specific_event.interface(),
367 generic_event.interface(),
368 "Registry interfaces do not match."
369 );
370 assert_eq!(
371 specific_event.registry_string(),
372 generic_event.registry_string(),
373 "Registry strings do not match."
374 );
375 assert_eq!(
376 specific_event.match_rule(),
377 generic_event.match_rule(),
378 "Match rule strings do not match."
379 );
380 assert_eq!(specific_event.path(), generic_event.path(), "Pathsdo not match.");
381 assert_eq!(specific_event.sender(), generic_event.sender(), "Senders do not match.");
382 }
383 };
384}
385
386// We decorate the macro with a `#[cfg(test)]` attribute.
387// This prevents Clippy from complaining about the macro not being used.
388// It is being used, but only in test mode.
389//
390/// As of writing, this macro is expanded only once: in the `event_test_cases!` macro.
391#[cfg(test)]
392macro_rules! zbus_message_test_case {
393 ($type:ty) => {
394 #[cfg(feature = "zbus")]
395 #[test]
396 fn zbus_msg_conversion_to_specific_event_type() {
397 let struct_event = <$type>::default();
398 let msg: zbus::Message = zbus::Message::try_from(struct_event.clone())
399 .expect("Should convert a `$type::default()` into a message. Check the `impl_to_dbus_message` macro .");
400 let struct_event_back =
401 <$type>::try_from(&msg).expect("Should convert from `$type::default()` originated `Message` back into a specific event type. Check the `impl_from_dbus_message` macro.");
402 assert_eq!(struct_event, struct_event_back);
403 }
404
405 #[cfg(feature = "zbus")]
406 #[test]
407 fn zbus_msg_conversion_to_event_enum_type() {
408 let struct_event = <$type>::default();
409 let msg: zbus::Message = zbus::Message::try_from(struct_event.clone()).expect("Should convert a `$type::default()` into a message. Check the `impl_to_dbus_message` macro .");
410 let event_enum_back =
411 Event::try_from(&msg).expect("Should convert a from `$type::default()` built `Message` into an event enum. Check the `impl_from_dbus_message` macro .");
412 let event_enum: Event = struct_event.into();
413 assert_eq!(event_enum, event_enum_back);
414 }
415 // make want to consider parameterized tests here, no need for fuzz testing, but one level lower than that may be nice
416 // try having a matching member, matching interface, path, or body type, but that has some other piece which is not right
417 #[cfg(feature = "zbus")]
418 #[test]
419 #[should_panic(expected = "Should panic")]
420 fn zbus_msg_conversion_failure_fake_msg() -> () {
421 let fake_msg = zbus::Message::signal(
422 "/org/a11y/sixtynine/fourtwenty",
423 "org.a11y.atspi.technically.valid",
424 "MadeUpMember",
425 )
426 .unwrap()
427 .sender(":0.0")
428 .unwrap()
429 .build(&())
430 .unwrap();
431 let event = <$type>::try_from(&fake_msg);
432 event.expect("Should panic");
433 }
434
435 #[cfg(feature = "zbus")]
436 #[test]
437 #[should_panic(expected = "Should panic")]
438 fn zbus_msg_conversion_failure_correct_interface() -> () {
439 let fake_msg = zbus::Message::signal(
440 "/org/a11y/sixtynine/fourtwenty",
441 <$type as BusProperties>::DBUS_INTERFACE,
442 "MadeUpMember",
443 )
444 .unwrap()
445 .sender(":0.0")
446 .unwrap()
447 .build(&())
448 .unwrap();
449 let event = <$type>::try_from(&fake_msg);
450 event.expect("Should panic");
451 }
452
453 #[cfg(feature = "zbus")]
454 #[test]
455 #[should_panic(expected = "Should panic")]
456 fn zbus_msg_conversion_failure_correct_interface_and_member() -> () {
457 let fake_msg = zbus::Message::signal(
458 "/org/a11y/sixtynine/fourtwenty",
459 <$type as BusProperties>::DBUS_INTERFACE,
460 <$type as BusProperties>::DBUS_MEMBER,
461 )
462 .unwrap()
463 .sender(":0.0")
464 .unwrap()
465 .build(&())
466 .unwrap();
467 let event = <$type>::try_from(&fake_msg);
468 event.expect("Should panic");
469 }
470
471 #[cfg(feature = "zbus")]
472 #[test]
473 #[should_panic(expected = "Should panic")]
474 fn zbus_msg_conversion_failure_correct_body() -> () {
475 let fake_msg = zbus::Message::signal(
476 "/org/a11y/sixtynine/fourtwenty",
477 "org.a11y.atspi.accessible.technically.valid",
478 "FakeMember",
479 )
480 .unwrap()
481 .sender(":0.0")
482 .unwrap()
483 .build(&<$type>::default().body())
484 .unwrap();
485 let event = <$type>::try_from(&fake_msg);
486 event.expect("Should panic");
487 }
488
489 #[cfg(feature = "zbus")]
490 #[test]
491 #[should_panic(expected = "Should panic")]
492 fn zbus_msg_conversion_failure_correct_body_and_member() -> () {
493 let fake_msg = zbus::Message::signal(
494 "/org/a11y/sixtynine/fourtwenty",
495 "org.a11y.atspi.accessible.technically.valid",
496 <$type as BusProperties>::DBUS_MEMBER,
497 )
498 .unwrap()
499 .sender(":0.0")
500 .unwrap()
501 .build(&<$type>::default().body())
502 .unwrap();
503 let event = <$type>::try_from(&fake_msg);
504 event.expect("Should panic");
505 }
506 };
507}
508
509/// Expands to five tests:
510///
511/// 1. `into_and_try_from_event`
512/// 2. `zbus_msg_invalid_interface`
513/// 3. `zbus_msg_invalid_member`
514/// 4. `zbus_msg_invalid_member_and_interface`
515/// 5. `zbus_msg_conversion`
516///
517/// # Examples
518///
519/// ```ignore
520/// event_wrapper_test_cases!(MouseEvents, AbsEvent);
521/// ```
522/// In the macro, its first argument `$type` is the event enum type.
523/// The second argument `$any_subtype` is the event struct type.
524///
525/// For each of the types, the macro will create a module with the name `events_tests_{foo}`
526/// where `{foo}` is the snake case of the 'interface enum' name.
527macro_rules! event_wrapper_test_cases {
528 ($type:ty, $any_subtype:ty) => {
529 #[cfg(test)]
530 #[rename_item::rename(name($type), prefix = "events_tests_", case = "snake")]
531 mod foo {
532 use super::{$any_subtype, $type, Event, BusProperties};
533 #[test]
534 fn into_and_try_from_event() {
535 // Create a default event struct from its type's `Default::default()` impl.
536 let sub_type = <$any_subtype>::default();
537 // Wrap the event struct in the event enum
538 let mod_type = <$type>::from(sub_type);
539 // Wrap the inner event enum into the `Event` enum.
540 let event = Event::from(mod_type.clone());
541 // Unwrap the `Event` enum into the inner event enum.
542 let mod_type2 = <$type>::try_from(event.clone())
543 .expect("Should convert outer `Event` enum into interface enum because it was created from it. Check the `impl_try_from_event_for_user_facing_event_type` macro");
544 assert_eq!(
545 mod_type, mod_type2,
546 "Events were able to be parsed and encapsulated, but they have changed value"
547 );
548 }
549 #[cfg(feature = "zbus")]
550 #[test]
551 #[should_panic(expected = "Should panic")]
552 fn zbus_msg_invalid_interface() {
553 let fake_msg = zbus::Message::signal(
554 "/org/a11y/sixtynine/fourtwenty",
555 "org.a11y.atspi.technically.valid.lol",
556 <$any_subtype as BusProperties>::DBUS_MEMBER,
557 )
558 .unwrap()
559 .sender(":0.0")
560 .unwrap()
561 .build(&<$any_subtype>::default().body())
562 .unwrap();
563
564 // It is hard to see what eventually is tested here. Let's unravel it:
565 //
566 // Below we call `TryFrom<&zbus::Message> for $type` where `$type` the interface enum name. (eg. `MouseEvents`, `ObjectEvents`, etc.) and
567 // `mod_type` is an 'interface enum' variant (eg. `MouseEvents::Abs(AbsEvent)`).
568 // This conversion is found in the `/src/events/{iface_name}.rs`` file.
569 // This conversion in turn leans on the `impl_from_dbus_message` macro.
570 // In `MouseEvents::Abs(msg.try_into()?)`, it is the `msg.try_into()?` that should fail.
571 // The `msg.try_into()?` is provided through the `impl_from_dbus_message` macro.
572 let mod_type = <$type>::try_from(&fake_msg);
573 mod_type.expect("Should panic");
574 }
575 #[cfg(feature = "zbus")]
576 #[test]
577 #[should_panic(expected = "Should panic")]
578 fn zbus_msg_invalid_member() {
579 let fake_msg = zbus::Message::signal(
580 "/org/a11y/sixtynine/fourtwenty",
581 <$any_subtype as BusProperties>::DBUS_INTERFACE,
582 "FakeFunctionLol",
583 )
584 .unwrap()
585 .sender(":0.0")
586 .unwrap()
587 .build(&<$any_subtype>::default().body())
588 .unwrap();
589 // As above, the `msg.try_into()?` is provided through the `impl_from_dbus_message` macro.
590 let mod_type = <$type>::try_from(&fake_msg);
591 mod_type.expect("Should panic");
592 }
593 #[cfg(feature = "zbus")]
594 #[test]
595 #[should_panic(expected = "Should panic")]
596 fn zbus_msg_invalid_member_and_interface() {
597 let fake_msg = zbus::Message::signal(
598 "/org/a11y/sixtynine/fourtwenty",
599 "org.a11y.atspi.technically.allowed",
600 "FakeFunctionLol",
601 )
602 .unwrap()
603 .sender(":0.0")
604 .unwrap()
605 .build(&<$any_subtype>::default().body())
606 .unwrap();
607 // As above, the `msg.try_into()?` is provided through the `impl_from_dbus_message` macro.
608 let mod_type = <$type>::try_from(&fake_msg);
609
610 // Note that the non-matching interface is the first error, so the member match error is not reached.
611 mod_type.expect("Should panic");
612 }
613 #[cfg(feature = "zbus")]
614 #[test]
615 fn zbus_msg_conversion() {
616 let valid_msg = zbus::Message::signal(
617 "/org/a11y/sixtynine/fourtwenty",
618 <$any_subtype as BusProperties>::DBUS_INTERFACE,
619 <$any_subtype as BusProperties>::DBUS_MEMBER,
620 )
621 .unwrap()
622 .sender(":0.0")
623 .unwrap()
624 .build(&<$any_subtype>::default().body())
625 .unwrap();
626 // As above, the `msg.try_into()?` is provided through the `impl_from_dbus_message` macro.
627 let mod_type = <$type>::try_from(&valid_msg);
628 mod_type.expect("Should convert from `$any_subtype::default()` built `Message` back into a interface event enum variant wrapping an inner type. Check the `impl_from_dbus_message` macro.");
629 }
630 }
631 };
632}
633
634macro_rules! event_test_cases {
635 ($type:ty) => {
636 #[cfg(test)]
637 #[rename_item::rename(name($type), prefix = "event_tests_", case = "snake")]
638 mod foo {
639 use super::{$type, Event, BusProperties, EventProperties, EventTypeProperties};
640
641 generic_event_test_case!($type);
642 event_enum_test_case!($type);
643 zbus_message_test_case!($type);
644 event_enum_transparency_test_case!($type);
645 }
646 assert_impl_all!(
647 $type: Clone,
648 std::fmt::Debug,
649 serde::Serialize,
650 serde::Deserialize<'static>,
651 Default,
652 PartialEq,
653 Eq,
654 std::hash::Hash,
655 crate::EventProperties,
656 crate::EventTypeProperties,
657 crate::BusProperties,
658 );
659 #[cfg(feature = "zbus")]
660 assert_impl_all!(zbus::Message: TryFrom<$type>);
661 };
662}
663