1use crate::AtspiError;
2use serde::{Deserialize, Serialize};
3use std::hash::{Hash, Hasher};
4use zbus_lockstep_macros::validate;
5use zbus_names::{BusName, UniqueName};
6use zvariant::{ObjectPath, Structure, Type};
7
8const NULL_PATH_STR: &str = "/org/a11y/atspi/null";
9const NULL_OBJECT_PATH: &ObjectPath<'static> =
10 &ObjectPath::from_static_str_unchecked(NULL_PATH_STR);
11
12#[cfg(test)]
13pub(crate) const TEST_OBJECT_BUS_NAME: &str = ":0.0";
14#[cfg(test)]
15pub(crate) const TEST_OBJECT_PATH_STR: &str = "/org/a11y/atspi/test/default";
16#[cfg(test)]
17pub(crate) const TEST_DEFAULT_OBJECT_REF: ObjectRef<'static> =
18 ObjectRef::from_static_str_unchecked(TEST_OBJECT_BUS_NAME, TEST_OBJECT_PATH_STR);
19
20#[validate(signal: "Available")]
29#[derive(Clone, Debug, Eq, Type)]
30#[zvariant(signature = "(so)")]
31pub enum ObjectRef<'o> {
32 Null,
33 Owned { name: UniqueName<'static>, path: ObjectPath<'static> },
34 Borrowed { name: UniqueName<'o>, path: ObjectPath<'o> },
35}
36
37impl<'o> ObjectRef<'o> {
38 #[must_use]
40 pub fn new(name: UniqueName<'o>, path: ObjectPath<'o>) -> Self {
41 Self::new_borrowed(name, path)
42 }
43
44 pub fn new_owned<N, P>(name: N, path: P) -> ObjectRefOwned
60 where
61 N: Into<UniqueName<'static>>,
62 P: Into<ObjectPath<'static>>,
63 {
64 let name: UniqueName<'static> = name.into();
65 let path: ObjectPath<'static> = path.into();
66
67 ObjectRefOwned(ObjectRef::Owned { name, path })
68 }
69
70 pub fn new_borrowed<N, P>(name: N, path: P) -> ObjectRef<'o>
86 where
87 N: Into<UniqueName<'o>>,
88 P: Into<ObjectPath<'o>>,
89 {
90 let name: UniqueName<'o> = name.into();
91 let path: ObjectPath<'o> = path.into();
92
93 ObjectRef::Borrowed { name, path }
94 }
95
96 pub fn try_from_bus_name_and_path(
101 sender: BusName<'o>,
102 path: ObjectPath<'o>,
103 ) -> Result<Self, AtspiError> {
104 if let BusName::Unique(unique_sender) = sender {
106 Ok(ObjectRef::new(unique_sender, path))
107 } else {
108 Err(AtspiError::ParseError("Expected UniqueName"))
109 }
110 }
111
112 #[must_use]
117 pub const fn from_static_str_unchecked(name: &'static str, path: &'static str) -> Self {
118 let name = UniqueName::from_static_str_unchecked(name);
119 let path = ObjectPath::from_static_str_unchecked(path);
120
121 ObjectRef::Owned { name, path }
122 }
123
124 #[must_use]
130 pub fn is_null(&self) -> bool {
131 matches!(self, Self::Null)
132 }
133
134 #[must_use]
153 pub fn name(&self) -> Option<&UniqueName<'o>> {
154 match self {
155 Self::Owned { name: own_name, .. } => Some(own_name),
156 Self::Borrowed { name: borrow_name, .. } => Some(borrow_name),
157 Self::Null => None,
158 }
159 }
160
161 #[must_use]
177 pub fn path(&self) -> &ObjectPath<'o> {
178 match self {
179 Self::Owned { path: own_path, .. } => own_path,
180 Self::Borrowed { path: borrow_path, .. } => borrow_path,
181 Self::Null => NULL_OBJECT_PATH,
182 }
183 }
184
185 #[must_use]
213 pub fn into_owned(self) -> ObjectRef<'static> {
214 match self {
215 Self::Null => ObjectRef::Null,
216 Self::Owned { name, path } => ObjectRef::Owned { name, path },
217 Self::Borrowed { name, path } => {
218 ObjectRef::Owned { name: name.to_owned(), path: path.to_owned() }
219 }
220 }
221 }
222
223 #[must_use]
225 pub fn name_as_str(&self) -> Option<&str> {
226 match self {
227 ObjectRef::Null => None,
228 ObjectRef::Owned { name, .. } | ObjectRef::Borrowed { name, .. } => Some(name.as_str()),
229 }
230 }
231
232 #[must_use]
234 pub fn path_as_str(&self) -> &str {
235 match self {
236 ObjectRef::Null => NULL_PATH_STR,
237 ObjectRef::Owned { path, .. } | ObjectRef::Borrowed { path, .. } => path.as_str(),
238 }
239 }
240}
241
242#[cfg(test)]
249impl Default for ObjectRef<'_> {
250 fn default() -> Self {
252 TEST_DEFAULT_OBJECT_REF
253 }
254}
255
256#[cfg(not(test))]
257impl Default for ObjectRef<'_> {
258 fn default() -> Self {
260 ObjectRef::Null
261 }
262}
263
264#[validate(signal: "Available")]
267#[derive(Clone, Debug, Default, Eq, Type)]
268pub struct ObjectRefOwned(pub(crate) ObjectRef<'static>);
269
270impl From<ObjectRef<'_>> for ObjectRefOwned {
271 fn from(object_ref: ObjectRef<'_>) -> Self {
280 ObjectRefOwned(object_ref.into_owned())
281 }
282}
283
284impl ObjectRefOwned {
285 #[must_use]
287 pub const fn new(object_ref: ObjectRef<'static>) -> Self {
288 Self(object_ref)
289 }
290
291 #[must_use]
296 pub const fn from_static_str_unchecked(name: &'static str, path: &'static str) -> Self {
297 let name = UniqueName::from_static_str_unchecked(name);
298 let path = ObjectPath::from_static_str_unchecked(path);
299
300 ObjectRefOwned(ObjectRef::Owned { name, path })
301 }
302
303 #[must_use]
305 pub fn is_null(&self) -> bool {
306 matches!(self.0, ObjectRef::Null)
307 }
308
309 #[must_use]
311 pub fn into_inner(self) -> ObjectRef<'static> {
312 self.0
313 }
314
315 #[must_use]
334 pub fn name(&self) -> Option<&UniqueName<'static>> {
335 match &self.0 {
336 ObjectRef::Owned { name, .. } | ObjectRef::Borrowed { name, .. } => Some(name),
337 ObjectRef::Null => None,
338 }
339 }
340
341 #[must_use]
357 pub fn path(&self) -> &ObjectPath<'static> {
358 match &self.0 {
359 ObjectRef::Owned { path, .. } | ObjectRef::Borrowed { path, .. } => path,
360 ObjectRef::Null => NULL_OBJECT_PATH,
361 }
362 }
363
364 #[must_use]
366 pub fn name_as_str(&self) -> Option<&str> {
367 match &self.0 {
368 ObjectRef::Null => None,
369 ObjectRef::Owned { name, .. } | ObjectRef::Borrowed { name, .. } => Some(name.as_str()),
370 }
371 }
372
373 #[must_use]
375 pub fn path_as_str(&self) -> &str {
376 match &self.0 {
377 ObjectRef::Null => NULL_PATH_STR,
378 ObjectRef::Owned { path, .. } | ObjectRef::Borrowed { path, .. } => path.as_str(),
379 }
380 }
381}
382
383impl Serialize for ObjectRef<'_> {
384 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
389 where
390 S: serde::Serializer,
391 {
392 match &self {
393 ObjectRef::Null => ("", NULL_OBJECT_PATH).serialize(serializer),
394 ObjectRef::Owned { name, path } | ObjectRef::Borrowed { name, path } => {
395 (name.as_str(), path).serialize(serializer)
396 }
397 }
398 }
399}
400
401impl Serialize for ObjectRefOwned {
402 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
404 where
405 S: serde::Serializer,
406 {
407 self.0.serialize(serializer)
408 }
409}
410
411impl<'de: 'o, 'o> Deserialize<'de> for ObjectRef<'o> {
412 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
417 where
418 D: serde::Deserializer<'de>,
419 {
420 struct ObjectRefVisitor;
421
422 impl<'de> serde::de::Visitor<'de> for ObjectRefVisitor {
423 type Value = ObjectRef<'de>;
424
425 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
426 formatter.write_str("a tuple of (&str, ObjectPath)")
427 }
428
429 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
430 where
431 A: serde::de::SeqAccess<'de>,
432 {
433 let name: &str = seq
434 .next_element()?
435 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
436 let path: ObjectPath<'de> = seq
437 .next_element()?
438 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
439
440 if path == *NULL_OBJECT_PATH {
441 Ok(ObjectRef::Null)
442 } else {
443 assert!(
444 !name.is_empty(),
445 "A non-null ObjectRef requires a name and a path but got: (\"\", {path})"
446 );
447 Ok(ObjectRef::Borrowed {
448 name: UniqueName::try_from(name).map_err(serde::de::Error::custom)?,
449 path,
450 })
451 }
452 }
453 }
454
455 deserializer.deserialize_tuple(2, ObjectRefVisitor)
456 }
457}
458
459impl<'de> Deserialize<'de> for ObjectRefOwned {
460 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
462 where
463 D: serde::Deserializer<'de>,
464 {
465 let object_ref: ObjectRef<'_> = Deserialize::deserialize(deserializer)?;
466 Ok(object_ref.into())
467 }
468}
469
470impl PartialEq for ObjectRef<'_> {
471 fn eq(&self, other: &Self) -> bool {
472 match (self, other) {
473 (ObjectRef::Null, ObjectRef::Null) => true,
475 (ObjectRef::Null, _) | (_, ObjectRef::Null) => false,
476 _ => self.name() == other.name() && self.path() == other.path(),
477 }
478 }
479}
480
481impl Hash for ObjectRef<'_> {
488 fn hash<H: Hasher>(&self, state: &mut H) {
489 match self {
490 ObjectRef::Null => {
491 "Null".hash(state);
493 }
494 ObjectRef::Owned { name, path } | ObjectRef::Borrowed { name, path } => {
495 name.as_str().hash(state);
496 path.as_str().hash(state);
497 }
498 }
499 }
500}
501
502impl Hash for ObjectRefOwned {
503 fn hash<H: Hasher>(&self, state: &mut H) {
504 self.0.hash(state);
505 }
506}
507
508impl PartialEq for ObjectRefOwned {
509 fn eq(&self, other: &Self) -> bool {
510 self.0 == other.0
511 }
512}
513
514impl PartialEq<ObjectRef<'_>> for ObjectRefOwned {
515 fn eq(&self, other: &ObjectRef<'_>) -> bool {
516 self.0 == *other
517 }
518}
519
520impl PartialEq<ObjectRefOwned> for ObjectRef<'_> {
521 fn eq(&self, other: &ObjectRefOwned) -> bool {
522 *self == other.0
523 }
524}
525
526#[cfg(feature = "zbus")]
527impl<'m: 'o, 'o> TryFrom<&'m zbus::message::Header<'_>> for ObjectRef<'o> {
528 type Error = crate::AtspiError;
529
530 fn try_from(header: &'m zbus::message::Header) -> Result<Self, Self::Error> {
555 let path = header.path().ok_or(crate::AtspiError::MissingPath)?;
556 let name = header.sender().ok_or(crate::AtspiError::MissingName)?;
557
558 Ok(ObjectRef::Borrowed { name: name.clone(), path: path.clone() })
559 }
560}
561
562#[cfg(feature = "zbus")]
563impl<'m> TryFrom<&'m zbus::message::Header<'_>> for ObjectRefOwned {
564 type Error = crate::AtspiError;
565
566 fn try_from(header: &'m zbus::message::Header) -> Result<Self, Self::Error> {
568 let path = header.path().ok_or(crate::AtspiError::MissingPath)?;
569 let name = header.sender().ok_or(crate::AtspiError::MissingName)?;
570
571 let object_ref =
572 ObjectRef::Owned { name: name.clone().into_owned(), path: path.clone().into_owned() };
573 Ok(ObjectRefOwned(object_ref))
574 }
575}
576
577impl<'v> TryFrom<zvariant::Value<'v>> for ObjectRef<'v> {
578 type Error = zvariant::Error;
579
580 fn try_from(value: zvariant::Value<'v>) -> Result<Self, Self::Error> {
581 let (name, path): (UniqueName, ObjectPath) = value.try_into()?;
583 Ok(ObjectRef::new_borrowed(name, path))
584 }
585}
586
587impl<'v> TryFrom<zvariant::Value<'v>> for ObjectRefOwned {
588 type Error = zvariant::Error;
589
590 fn try_from(value: zvariant::Value<'v>) -> Result<Self, Self::Error> {
591 let (name, path): (UniqueName, ObjectPath) = value.try_into()?;
593 Ok(ObjectRef::new_borrowed(name, path).into())
594 }
595}
596
597impl TryFrom<zvariant::OwnedValue> for ObjectRef<'static> {
598 type Error = zvariant::Error;
599 fn try_from(value: zvariant::OwnedValue) -> Result<Self, Self::Error> {
600 let (name, path): (UniqueName<'static>, ObjectPath<'static>) = value.try_into()?;
601 Ok(ObjectRef::Owned { name, path })
602 }
603}
604
605impl TryFrom<zvariant::OwnedValue> for ObjectRefOwned {
606 type Error = zvariant::Error;
607 fn try_from(value: zvariant::OwnedValue) -> Result<Self, Self::Error> {
608 let (name, path): (UniqueName<'static>, ObjectPath<'static>) = value.try_into()?;
609 let obj = ObjectRef::Owned { name, path };
610 Ok(ObjectRefOwned(obj))
611 }
612}
613
614impl<'reference: 'structure, 'object: 'structure, 'structure> From<&'reference ObjectRef<'object>>
615 for zvariant::Structure<'structure>
616{
617 fn from(obj: &'reference ObjectRef<'object>) -> Self {
618 match obj {
619 ObjectRef::Null => ("", NULL_OBJECT_PATH).into(),
620 ObjectRef::Borrowed { name, path } => Structure::from((name.clone(), path)),
621 ObjectRef::Owned { name, path } => Structure::from((name.as_str(), path.as_ref())),
622 }
623 }
624}
625
626impl<'o> From<ObjectRef<'o>> for zvariant::Structure<'o> {
627 fn from(obj: ObjectRef<'o>) -> Self {
628 match obj {
629 ObjectRef::Null => Structure::from(("", NULL_OBJECT_PATH)),
630 ObjectRef::Borrowed { name, path } | ObjectRef::Owned { name, path } => {
631 Structure::from((name, path))
632 }
633 }
634 }
635}
636
637impl From<ObjectRefOwned> for zvariant::Structure<'_> {
638 fn from(obj: ObjectRefOwned) -> Self {
639 let object_ref = obj.into_inner();
640 object_ref.into()
641 }
642}
643
644#[cfg(test)]
645mod tests {
646 use std::hash::{DefaultHasher, Hash, Hasher};
647
648 use super::ObjectRef;
649 use crate::object_ref::{NULL_OBJECT_PATH, NULL_PATH_STR};
650 use zbus::zvariant;
651 use zbus::{names::UniqueName, zvariant::ObjectPath};
652 use zvariant::{serialized::Context, to_bytes, OwnedValue, Value, LE};
653
654 const TEST_OBJECT_PATH: &str = "/org/a11y/atspi/path/007";
655
656 #[test]
657 fn owned_object_ref_creation() {
658 let name = UniqueName::from_static_str_unchecked(":1.23");
659 let path = ObjectPath::from_static_str_unchecked(TEST_OBJECT_PATH);
660
661 let object_ref = ObjectRef::new_owned(name, path);
662
663 assert_eq!(object_ref.name_as_str(), Some(":1.23"));
664 assert_eq!(object_ref.path_as_str(), TEST_OBJECT_PATH);
665 }
666
667 #[test]
668 fn borrowed_object_ref_creation() {
669 let object_ref = ObjectRef::new_borrowed(
670 UniqueName::from_static_str(":1.23").unwrap(),
671 ObjectPath::from_static_str_unchecked(TEST_OBJECT_PATH),
672 );
673 assert_eq!(object_ref.name_as_str(), Some(":1.23"));
674 assert_eq!(object_ref.path_as_str(), TEST_OBJECT_PATH);
675 }
676
677 #[test]
678 fn null_object_ref() {
679 let null_object_ref: ObjectRef = ObjectRef::Null;
680 assert!(null_object_ref.is_null());
681 assert!(null_object_ref.name().is_none());
682 assert_eq!(null_object_ref.path(), NULL_OBJECT_PATH);
683 }
684
685 #[test]
686 fn object_ref_into_owned() {
687 let borrowed_object_ref = ObjectRef::new_borrowed(
688 UniqueName::from_static_str(":1.23").unwrap(),
689 ObjectPath::from_static_str_unchecked(TEST_OBJECT_PATH),
690 );
691 let owned_object_ref = borrowed_object_ref.into_owned();
692 assert!(matches!(owned_object_ref, ObjectRef::Owned { .. }));
693 assert_eq!(owned_object_ref.name_as_str(), Some(":1.23"));
694 assert_eq!(owned_object_ref.path_as_str(), TEST_OBJECT_PATH);
695 }
696
697 #[test]
698 fn object_ref_into_name_and_path() {
699 let object_ref = ObjectRef::new_borrowed(
700 UniqueName::from_static_str(":1.23").unwrap(),
701 ObjectPath::from_static_str_unchecked(TEST_OBJECT_PATH),
702 );
703 let name = object_ref.name().unwrap();
704 let path = object_ref.path();
705 assert_eq!(name.as_str(), ":1.23");
706 assert_eq!(path.as_str(), TEST_OBJECT_PATH);
707 }
708
709 #[test]
710 fn serialization_null_object_ref() {
711 let null_object_ref: ObjectRef = ObjectRef::Null;
712 assert!(null_object_ref.is_null());
713
714 let ctxt = Context::new_dbus(LE, 0);
715 let encoded = to_bytes(ctxt, &null_object_ref).unwrap();
716
717 let (obj, _) = encoded.deserialize::<ObjectRef>().unwrap();
718
719 assert!(obj.is_null());
720 assert!(obj.name().is_none());
721 assert_eq!(obj.path(), NULL_OBJECT_PATH);
722 }
723
724 #[test]
725 fn serialization_owned_object_ref() {
726 let name = UniqueName::from_static_str_unchecked(":1.23");
727 let path = ObjectPath::from_static_str_unchecked(TEST_OBJECT_PATH);
728
729 let object_ref = ObjectRef::new_owned(name, path);
730
731 let ctxt = Context::new_dbus(LE, 0);
732 let encoded = to_bytes(ctxt, &object_ref).unwrap();
733
734 let (obj, _) = encoded.deserialize::<ObjectRef>().unwrap();
735
736 assert!(matches!(obj, ObjectRef::Borrowed { .. }));
740 assert_eq!(obj.name().unwrap().as_str(), ":1.23");
741 assert_eq!(obj.path_as_str(), TEST_OBJECT_PATH);
742 }
743
744 #[test]
745 fn serialization_borrowed_object_ref() {
746 let object_ref = ObjectRef::new_borrowed(
747 UniqueName::from_static_str(":1.23").unwrap(),
748 ObjectPath::from_static_str_unchecked(TEST_OBJECT_PATH),
749 );
750
751 let ctxt = Context::new_dbus(LE, 0);
752 let encoded = to_bytes(ctxt, &object_ref).unwrap();
753
754 let (obj, _) = encoded.deserialize::<ObjectRef>().unwrap();
755 assert!(matches!(obj, ObjectRef::Borrowed { .. }));
756
757 assert_eq!(obj.name().unwrap().as_str(), ":1.23");
758 assert_eq!(obj.path_as_str(), TEST_OBJECT_PATH);
759 }
760
761 #[test]
762 fn object_ref_equality() {
763 let object_ref1 = ObjectRef::new_borrowed(
764 UniqueName::from_static_str(":1.23").unwrap(),
765 ObjectPath::from_static_str_unchecked(TEST_OBJECT_PATH),
766 );
767 let object_ref2 = ObjectRef::new_borrowed(
768 UniqueName::from_static_str(":1.23").unwrap(),
769 ObjectPath::from_static_str_unchecked(TEST_OBJECT_PATH),
770 );
771 assert_eq!(object_ref1, object_ref2);
772
773 let object_ref3 = ObjectRef::new_borrowed(
774 UniqueName::from_static_str(":1.24").unwrap(),
775 ObjectPath::from_static_str_unchecked(TEST_OBJECT_PATH),
776 );
777 assert_ne!(object_ref1, object_ref3);
778
779 let object_ref4 = ObjectRef::new_owned(
780 UniqueName::from_static_str_unchecked(":1.23"),
781 ObjectPath::from_static_str_unchecked(TEST_OBJECT_PATH),
782 );
783 assert_eq!(object_ref1, object_ref4);
784
785 let null_object_ref: ObjectRef = ObjectRef::Null;
786 assert_ne!(object_ref1, null_object_ref);
787 assert_ne!(null_object_ref, object_ref1);
788
789 let null_object_ref2: ObjectRef = ObjectRef::Null;
790 assert_eq!(null_object_ref, null_object_ref2);
791 }
792
793 #[test]
794 fn try_from_value_for_objectref() {
795 let name = UniqueName::from_static_str_unchecked(":0.0");
796 let path = ObjectPath::from_static_str_unchecked("/org/a11y/atspi/testpath");
797
798 let objref = ObjectRef::new_borrowed(name, path);
799 let value: Value = objref.into();
800
801 let objref_2: ObjectRef = value.try_into().unwrap();
802
803 assert_eq!(objref_2.name().unwrap().as_str(), ":0.0");
804 assert_eq!(objref_2.path_as_str(), "/org/a11y/atspi/testpath");
805 }
806
807 #[test]
808 fn try_from_owned_value_for_objectref() {
809 let name = UniqueName::from_static_str_unchecked(":0.0");
810 let path = ObjectPath::from_static_str_unchecked("/org/a11y/atspi/testpath");
811
812 let objref = ObjectRef::new_borrowed(name, path);
813
814 let value: Value = objref.into();
815 let value: OwnedValue = value.try_into().unwrap();
816 let objref_2: ObjectRef = value.try_into().unwrap();
817
818 assert_eq!(objref_2.name_as_str(), Some(":0.0"));
819 assert_eq!(objref_2.path_as_str(), "/org/a11y/atspi/testpath");
820 }
821
822 #[test]
825 fn must_fail_test_try_from_invalid_value_for_object_ref() {
826 let value = zvariant::Value::from((42, true));
827 let obj: Result<ObjectRef, _> = value.try_into();
828 assert!(obj.is_err());
829 }
830
831 #[test]
832 fn hash_and_object_coherence() {
833 let name = UniqueName::from_static_str_unchecked(":1.23");
834 let path = ObjectPath::from_static_str_unchecked(TEST_OBJECT_PATH);
835
836 let object_ref1 = ObjectRef::new_borrowed(&name, &path);
837 let object_ref2 = ObjectRef::new_borrowed(name, path);
838
839 let mut hasher1 = DefaultHasher::new();
840 let mut hasher2 = DefaultHasher::new();
841 assert_eq!(object_ref1, object_ref2);
842 object_ref1.hash(&mut hasher1);
843 object_ref2.hash(&mut hasher2);
844 assert_eq!(hasher1.finish(), hasher2.finish());
845 }
846
847 #[test]
848 #[should_panic(expected = "assertion failed: matches!(obj, ObjectRef::Borrowed { .. })")]
849 fn valid_name_null_path_object_ref() {
850 let object_ref = ObjectRef::from_static_str_unchecked("1.23", NULL_PATH_STR);
851
852 let ctxt = Context::new_dbus(LE, 0);
853 let encoded = to_bytes(ctxt, &object_ref).unwrap();
854
855 let (obj, _) = encoded.deserialize::<ObjectRef>().unwrap();
856 assert!(matches!(obj, ObjectRef::Borrowed { .. }));
857 }
858
859 #[test]
861 #[should_panic(
862 expected = r#"A non-null ObjectRef requires a name and a path but got: ("", /org/a11y/atspi/path/007)"#
863 )]
864 fn empty_name_valid_path_object_ref() {
865 let object_ref = ObjectRef::from_static_str_unchecked("", TEST_OBJECT_PATH);
866
867 let ctxt = Context::new_dbus(LE, 0);
868 let encoded = to_bytes(ctxt, &object_ref).unwrap();
869
870 let (_obj, _) = encoded.deserialize::<ObjectRef>().unwrap();
871 }
872}