atspi_common/
object_ref.rs1use serde::{Deserialize, Serialize};
2use zbus_lockstep_macros::validate;
3use zbus_names::{OwnedUniqueName, UniqueName};
4use zvariant::{ObjectPath, OwnedObjectPath, Type, Value};
5
6#[validate(signal: "Available")]
15#[derive(Debug, Clone, Serialize, Deserialize, Type, PartialEq, Eq, Hash)]
16pub struct ObjectRef {
17 pub name: OwnedUniqueName,
18 pub path: OwnedObjectPath,
19}
20
21impl Default for ObjectRef {
22 fn default() -> Self {
23 ObjectRef {
24 name: UniqueName::from_static_str_unchecked(":0.0").into(),
25 path: ObjectPath::from_static_str_unchecked("/org/a11y/atspi/accessible/null").into(),
26 }
27 }
28}
29
30impl ObjectRef {
31 #[must_use]
33 pub fn new<'a>(sender: UniqueName<'a>, path: ObjectPath<'a>) -> Self {
34 Self { name: sender.into(), path: path.into() }
35 }
36
37 #[must_use]
42 pub fn from_static_str_unchecked(sender: &'static str, path: &'static str) -> Self {
43 Self {
44 name: UniqueName::from_static_str_unchecked(sender).into(),
45 path: ObjectPath::from_static_str_unchecked(path).into(),
46 }
47 }
48}
49
50#[validate(signal: "Available")]
61#[derive(Debug, Clone, Serialize, Deserialize, Type, PartialEq, Eq, Hash)]
62pub struct ObjectRefBorrowed<'a> {
63 #[serde(borrow)]
64 pub name: UniqueName<'a>,
65 #[serde(borrow)]
66 pub path: ObjectPath<'a>,
67}
68
69impl ObjectRefBorrowed<'_> {
70 #[must_use]
74 pub fn to_fully_owned(&self) -> ObjectRef {
75 let name = OwnedUniqueName::from(self.name.clone());
76 let path = OwnedObjectPath::from(self.path.clone());
77 ObjectRef { name, path }
78 }
79}
80
81impl Default for ObjectRefBorrowed<'_> {
82 fn default() -> Self {
83 ObjectRefBorrowed {
84 name: UniqueName::from_static_str_unchecked(":0.0"),
85 path: ObjectPath::from_static_str_unchecked("/org/a11y/atspi/accessible/null"),
86 }
87 }
88}
89
90impl<'a> TryFrom<zvariant::Value<'a>> for ObjectRef {
91 type Error = zvariant::Error;
92 fn try_from(value: zvariant::Value<'a>) -> Result<Self, Self::Error> {
93 let (name, path): (OwnedUniqueName, OwnedObjectPath) = value.try_to_owned()?.try_into()?;
95 Ok(ObjectRef { name, path })
96 }
97}
98
99impl TryFrom<zvariant::OwnedValue> for ObjectRef {
100 type Error = zvariant::Error;
101 fn try_from(value: zvariant::OwnedValue) -> Result<Self, Self::Error> {
102 let (name, path): (OwnedUniqueName, OwnedObjectPath) = value.try_into()?;
103 Ok(ObjectRef { name, path })
104 }
105}
106
107impl<'a> TryFrom<Value<'a>> for ObjectRefBorrowed<'a> {
108 type Error = zvariant::Error;
109 fn try_from(value: zvariant::Value<'a>) -> Result<Self, Self::Error> {
110 let (name, path): (UniqueName, ObjectPath) = value.try_into()?;
111 Ok(ObjectRefBorrowed { name, path })
112 }
113}
114
115impl From<ObjectRef> for zvariant::Structure<'_> {
116 fn from(obj: ObjectRef) -> Self {
117 (obj.name, obj.path).into()
118 }
119}
120
121#[cfg(feature = "zbus")]
122impl TryFrom<&zbus::message::Header<'_>> for ObjectRef {
123 type Error = crate::AtspiError;
124 fn try_from(header: &zbus::message::Header) -> Result<Self, Self::Error> {
125 let path = header.path().ok_or(crate::AtspiError::MissingPath)?;
126 let owned_path: OwnedObjectPath = path.clone().into();
127
128 let sender: UniqueName<'_> = header.sender().ok_or(crate::AtspiError::MissingName)?.into();
129 let name: OwnedUniqueName = sender.to_owned().into();
130
131 Ok(ObjectRef { name, path: owned_path })
132 }
133}
134
135#[cfg(test)]
136mod test {
137 use crate::{object_ref::ObjectRefBorrowed, ObjectRef};
138 use zvariant::Value;
139
140 #[test]
141 fn test_accessible_from_dbus_ctxt_to_object_ref() {
142 use zvariant::serialized::Context;
143 use zvariant::{to_bytes, Value, LE};
144
145 let acc = ObjectRef::default();
146 let ctxt = Context::new_dbus(LE, 0);
147 let acc_value: Value<'_> = acc.into();
148 let data = to_bytes(ctxt, &acc_value).unwrap();
149 let (value, _) = data.deserialize::<Value>().unwrap();
150 let accessible: ObjectRef = value.try_into().unwrap();
151
152 assert_eq!(accessible.name.as_str(), ":0.0");
153 assert_eq!(accessible.path.as_str(), "/org/a11y/atspi/accessible/null");
154 }
155
156 #[test]
157 fn test_accessible_value_wrapped_from_dbus_ctxt_to_object_ref() {
158 use zvariant::serialized::Context;
159 use zvariant::{to_bytes, Value, LE};
160
161 let acc = ObjectRef::default();
162 let value: zvariant::Value = acc.into();
163 let ctxt = Context::new_dbus(LE, 0);
164 let encoded = to_bytes(ctxt, &value).unwrap();
165 let (value, _) = encoded.deserialize::<Value>().unwrap();
166 let accessible: ObjectRef = value.try_into().unwrap();
167
168 assert_eq!(accessible.name.as_str(), ":0.0");
169 assert_eq!(accessible.path.as_str(), "/org/a11y/atspi/accessible/null");
170 }
171
172 #[test]
173 fn test_try_from_value_for_object_ref() {
174 use zvariant::Value;
175
176 let oref = ObjectRef::default();
177 let value: Value = oref.into();
178 let obj: ObjectRef = value.try_into().unwrap();
179
180 assert_eq!(obj.name.as_str(), ":0.0");
181 assert_eq!(obj.path.as_str(), "/org/a11y/atspi/accessible/null");
182 }
183
184 #[test]
185 fn test_try_from_owned_value_for_object_ref() {
186 use zvariant::OwnedValue;
187 use zvariant::Value;
188
189 let oref = ObjectRef::default();
190 let value: Value = oref.into();
191 let value: OwnedValue = value.try_into().unwrap();
192 let obj: ObjectRef = value.try_into().unwrap();
193
194 assert_eq!(obj.name.as_str(), ":0.0");
195 assert_eq!(obj.path.as_str(), "/org/a11y/atspi/accessible/null");
196 }
197
198 #[test]
199 fn must_fail_test_try_from_invalid_value_for_object_ref() {
200 let value = zvariant::Value::from(42);
201 let obj: Result<ObjectRef, _> = value.try_into();
202 assert!(obj.is_err());
203 }
204
205 #[test]
206 fn test_try_from_value_for_object_ref_borrow() {
207 use zvariant::Value;
208
209 let oref = ObjectRef::default();
210 let value: Value = oref.into();
211 let obj_borrow: ObjectRefBorrowed = value.try_into().unwrap();
212
213 assert_eq!(obj_borrow.name.as_str(), ":0.0");
214 assert_eq!(obj_borrow.path.as_str(), "/org/a11y/atspi/accessible/null");
215 }
216
217 #[test]
218 fn must_fail_test_try_from_invalid_value_for_object_ref_borrow() {
219 let value = zvariant::Value::from((42, true));
220 let obj: Result<ObjectRefBorrowed, _> = value.try_into();
221 assert!(obj.is_err());
222 }
223
224 #[test]
225 fn test_objectref_default_doesnt_panic() {
226 let objr = ObjectRef::default();
227 assert_eq!(objr.name.as_str(), ":0.0");
228 assert_eq!(objr.path.as_str(), "/org/a11y/atspi/accessible/null");
229 }
230
231 #[test]
232 fn try_into_value() {
233 let objr = ObjectRef::default();
234 let value_struct = Value::from(objr);
235 let Value::Structure(structure) = value_struct else {
236 panic!("Unable to destructure a structure out of the Value.");
237 };
238 let vals = structure.into_fields();
239 assert_eq!(vals.len(), 2);
240 let Value::Str(bus_name) = vals.first().unwrap() else {
241 panic!("Unable to destructure field value: {:?}", vals.first().unwrap());
242 };
243 assert_eq!(bus_name, ":0.0");
244 let Value::ObjectPath(path) = vals.last().unwrap() else {
245 panic!("Unable to destructure field value: {:?}", vals.get(1).unwrap());
246 };
247 assert_eq!(path.as_str(), "/org/a11y/atspi/accessible/null");
248 }
249}