atspi_common/
accessible.rs

1use crate::events::signatures_are_eq;
2use serde::{Deserialize, Serialize};
3use zvariant::{ObjectPath, OwnedObjectPath, Signature, Type};
4
5pub const ACCESSIBLE_PAIR_SIGNATURE: Signature<'_> = Signature::from_static_str_unchecked("(so)");
6
7// TODO: Try to make borrowed versions work,
8// check where the lifetimes of the borrow are tied to, see also: comment on `interface()` method
9// in `DefaultEvent` impl
10// then rename into Owned for this one.
11/// Owned Accessible type
12/// Emitted by `CacheRemove` and `Available`
13#[derive(Debug, Clone, Serialize, Deserialize, Type, PartialEq, Eq, Hash)]
14pub struct Accessible {
15	pub name: String,
16	pub path: OwnedObjectPath,
17}
18
19impl Default for Accessible {
20	fn default() -> Self {
21		Accessible {
22			name: ":0.0".into(),
23			path: ObjectPath::from_static_str("/org/a11y/atspi/accessible/null")
24				.unwrap()
25				.into(),
26		}
27	}
28}
29
30#[test]
31fn test_accessible_signature() {
32	assert_eq!(
33		Accessible::signature(),
34		ACCESSIBLE_PAIR_SIGNATURE,
35		"Accessible does not have the correct type."
36	);
37}
38
39#[test]
40fn test_accessible_from_dbus_ctxt_to_accessible() {
41	use zvariant::{from_slice, to_bytes, EncodingContext as Context, Value};
42
43	let acc = Accessible::default();
44	let ctxt = Context::<byteorder::LE>::new_dbus(0);
45	let acc_value: Value<'_> = acc.try_into().unwrap();
46	let encoded = to_bytes(ctxt, &acc_value).unwrap();
47	let decoded: Value = from_slice(&encoded, ctxt).unwrap();
48	let accessible: Accessible = decoded.try_into().unwrap();
49
50	assert_eq!(accessible.name.as_str(), ":0.0");
51	assert_eq!(accessible.path.as_str(), "/org/a11y/atspi/accessible/null");
52}
53
54#[test]
55fn test_accessible_value_wrapped_from_dbus_ctxt_to_accessible() {
56	use zvariant::{from_slice, to_bytes, EncodingContext as Context, Value};
57
58	let acc = Accessible::default();
59	let value: zvariant::Value = acc.into();
60	let ctxt = Context::<byteorder::LE>::new_dbus(0);
61	let encoded = to_bytes(ctxt, &value).unwrap();
62	let decoded: Value = from_slice(&encoded, ctxt).unwrap();
63	let accessible: Accessible = decoded.try_into().unwrap();
64
65	assert_eq!(accessible.name.as_str(), ":0.0");
66	assert_eq!(accessible.path.as_str(), "/org/a11y/atspi/accessible/null");
67}
68
69impl<'a> TryFrom<zvariant::Value<'a>> for Accessible {
70	type Error = zvariant::Error;
71	fn try_from(value: zvariant::Value<'a>) -> Result<Self, Self::Error> {
72		value.to_owned().try_into()
73	}
74}
75
76impl TryFrom<zvariant::OwnedValue> for Accessible {
77	type Error = zvariant::Error;
78	fn try_from<'a>(value: zvariant::OwnedValue) -> Result<Self, Self::Error> {
79		match &*value {
80			zvariant::Value::Structure(s) => {
81				if !signatures_are_eq(&s.signature(), &ACCESSIBLE_PAIR_SIGNATURE) {
82					return Err(zvariant::Error::SignatureMismatch(s.signature(), format!("To turn a zvariant::Value into an atspi::Accessible, it must be of type {}", ACCESSIBLE_PAIR_SIGNATURE.as_str())));
83				}
84				let fields = s.fields();
85				let name: String =
86					fields.get(0).ok_or(zvariant::Error::IncorrectType)?.try_into()?;
87				let path_value: ObjectPath<'_> =
88					fields.get(1).ok_or(zvariant::Error::IncorrectType)?.try_into()?;
89				Ok(Accessible { name, path: path_value.into() })
90			}
91			_ => Err(zvariant::Error::IncorrectType),
92		}
93	}
94}
95
96impl From<Accessible> for zvariant::Structure<'_> {
97	fn from(accessible: Accessible) -> Self {
98		(accessible.name.as_str().to_string(), accessible.path).into()
99	}
100}