atspi_common/
object_ref.rs

1use serde::{Deserialize, Serialize};
2use zbus_lockstep_macros::validate;
3use zbus_names::{OwnedUniqueName, UniqueName};
4use zvariant::{ObjectPath, OwnedObjectPath, Signature, Type};
5
6pub const OBJECT_REF_SIGNATURE: Signature<'_> = Signature::from_static_str_unchecked("(so)");
7
8/// `ObjectRef` type
9///
10/// A ubiquitous type used to refer to an object in the accessibility tree.
11///
12/// In AT-SPI2, objects in the applications' UI object tree are uniquely identified
13/// using a server name and object path. "(so)"
14///
15/// Emitted by `RemoveAccessible` and `Available`
16#[validate(signal: "Available")]
17#[derive(Debug, Clone, Serialize, Deserialize, Type, PartialEq, Eq, Hash)]
18pub struct ObjectRef {
19	pub name: OwnedUniqueName,
20	pub path: OwnedObjectPath,
21}
22
23impl Default for ObjectRef {
24	fn default() -> Self {
25		ObjectRef {
26			name: UniqueName::from_static_str(":0.0").unwrap().into(),
27			path: ObjectPath::from_static_str("/org/a11y/atspi/accessible/null")
28				.unwrap()
29				.into(),
30		}
31	}
32}
33
34#[cfg(test)]
35#[test]
36fn test_accessible_from_dbus_ctxt_to_accessible() {
37	use zvariant::serialized::Context;
38	use zvariant::{to_bytes, Value, LE};
39
40	let acc = ObjectRef::default();
41	let ctxt = Context::new_dbus(LE, 0);
42	let acc_value: Value<'_> = acc.into();
43	let data = to_bytes(ctxt, &acc_value).unwrap();
44	let (value, _) = data.deserialize::<Value>().unwrap();
45	let accessible: ObjectRef = value.try_into().unwrap();
46
47	assert_eq!(accessible.name.as_str(), ":0.0");
48	assert_eq!(accessible.path.as_str(), "/org/a11y/atspi/accessible/null");
49}
50
51#[cfg(test)]
52#[test]
53fn test_accessible_value_wrapped_from_dbus_ctxt_to_accessible() {
54	use zvariant::serialized::Context;
55	use zvariant::{to_bytes, Value, LE};
56
57	let acc = ObjectRef::default();
58	let value: zvariant::Value = acc.into();
59	let ctxt = Context::new_dbus(LE, 0);
60	let encoded = to_bytes(ctxt, &value).unwrap();
61	let (value, _) = encoded.deserialize::<Value>().unwrap();
62	let accessible: ObjectRef = value.try_into().unwrap();
63
64	assert_eq!(accessible.name.as_str(), ":0.0");
65	assert_eq!(accessible.path.as_str(), "/org/a11y/atspi/accessible/null");
66}
67
68impl<'a> TryFrom<zvariant::Value<'a>> for ObjectRef {
69	type Error = zvariant::Error;
70	fn try_from(value: zvariant::Value<'a>) -> Result<Self, Self::Error> {
71		value.try_to_owned()?.try_into()
72	}
73}
74
75impl TryFrom<zvariant::OwnedValue> for ObjectRef {
76	type Error = zvariant::Error;
77	fn try_from<'a>(value: zvariant::OwnedValue) -> Result<Self, Self::Error> {
78		match &*value {
79			zvariant::Value::Structure(s) => {
80				if s.signature() != OBJECT_REF_SIGNATURE {
81					return Err(zvariant::Error::SignatureMismatch(s.signature(), format!("To turn a zvariant::Value into an atspi::ObjectRef, it must be of type {}", OBJECT_REF_SIGNATURE.as_str())));
82				}
83				let fields = s.fields();
84				let name: String =
85					fields.first().ok_or(zvariant::Error::IncorrectType)?.try_into()?;
86				let path_value: ObjectPath<'_> =
87					fields.last().ok_or(zvariant::Error::IncorrectType)?.try_into()?;
88				Ok(ObjectRef {
89					name: name.try_into().map_err(|_| zvariant::Error::IncorrectType)?,
90					path: path_value.into(),
91				})
92			}
93			_ => Err(zvariant::Error::IncorrectType),
94		}
95	}
96}
97
98impl From<ObjectRef> for zvariant::Structure<'_> {
99	fn from(obj: ObjectRef) -> Self {
100		(obj.name, obj.path).into()
101	}
102}