atspi_common/
interface.rs

1//! Conversion functions and types representing a set of [`Interface`]s.
2//!
3//! Each `AccessibleProxy` will implement some set of these interfaces,
4//! represented by a [`InterfaceSet`].
5
6use enumflags2::{bitflags, BitFlag, BitFlags};
7use serde::{
8	de::{self, Deserialize, Deserializer, Visitor},
9	ser::{Serialize, Serializer},
10};
11use std::fmt;
12use zvariant::{Signature, Type};
13
14const ACCESSIBLE_INTERFACE_NAME: &str = "org.a11y.atspi.Accessible";
15const ACTION_INTERFACE_NAME: &str = "org.a11y.atspi.Action";
16const APPLICATION_INTERFACE_NAME: &str = "org.a11y.atspi.Application";
17const CACHE_INTERFACE_NAME: &str = "org.a11y.atspi.Cache";
18const COLLECTION_INTERFACE_NAME: &str = "org.a11y.atspi.Collection";
19const COMPONENT_INTERFACE_NAME: &str = "org.a11y.atspi.Component";
20const DOCUMENT_INTERFACE_NAME: &str = "org.a11y.atspi.Document";
21const DEVICE_EVENT_CONTROLLER_INTERFACE_NAME: &str = "org.a11y.atspi.DeviceEventController";
22const DEVICE_EVENT_LISTENER_INTERFACE_NAME: &str = "org.a11y.atspi.DeviceEventListener";
23const EDITABLE_TEXT_INTERFACE_NAME: &str = "org.a11y.atspi.EditableText";
24const HYPERLINK_INTERFACE_NAME: &str = "org.a11y.atspi.Hyperlink";
25const HYPERTEXT_INTERFACE_NAME: &str = "org.a11y.atspi.Hypertext";
26const IMAGE_INTERFACE_NAME: &str = "org.a11y.atspi.Image";
27const REGISTRY_INTERFACE_NAME: &str = "org.a11y.atspi.Registry";
28const SELECTION_INTERFACE_NAME: &str = "org.a11y.atspi.Selection";
29const SOCKET_INTERFACE_NAME: &str = "org.a11y.atspi.Socket";
30const TABLE_INTERFACE_NAME: &str = "org.a11y.atspi.Table";
31const TABLE_CELL_INTERFACE_NAME: &str = "org.a11y.atspi.TableCell";
32const TEXT_INTERFACE_NAME: &str = "org.a11y.atspi.Text";
33const VALUE_INTERFACE_NAME: &str = "org.a11y.atspi.Value";
34
35/// AT-SPI interfaces an accessible object can implement.
36#[bitflags]
37#[repr(u32)]
38#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39pub enum Interface {
40	/// Interface to indicate implementation of `AccessibleProxy`.
41	Accessible,
42	/// Interface to indicate implementation of `ActionProxy`.
43	Action,
44	/// Interface to indicate implementation of `ApplicationProxy`.
45	Application,
46	/// Interface to indicate implementation of `CacheProxy`.
47	Cache,
48	/// Interface to indicate implementation of `CollectionProxy`.
49	Collection,
50	/// Interface to indicate implementation of `ComponentProxy`.
51	Component,
52	/// Interface to indicate implementation of `DocumentProxy`.
53	Document,
54	/// Interface to indicate implementation of `DeviceEventControllerProxy`.
55	DeviceEventController,
56	/// Interface to indicate implementation of `DeviceEventListenerProxy`.
57	DeviceEventListener,
58	/// Interface to indicate implementation of `EditableTextProxy`.
59	EditableText,
60	/// Interface to indicate implementation of `HyperlinkProxy`.
61	Hyperlink,
62	/// Interface to indicate implementation of `HypertextProxy`.
63	Hypertext,
64	/// Interface to indicate implementation of `ImageProxy`.
65	Image,
66	/// Interface to indicate implementation of `RegistryProxy`.
67	Registry,
68	/// Interface to indicate implementation of `SelectionProxy`.
69	Selection,
70	/// Interface to indicate implementation of `SocketProxy`.
71	Socket,
72	/// Interface to indicate implementation of `TableProxy`.
73	Table,
74	/// Interface to indicate implementation of `TableCellProxy`.
75	TableCell,
76	/// Interface to indicate implementation of `TextProxy`.
77	Text,
78	/// Interface to indicate implementation of `ValueProxy`.
79	Value,
80}
81
82impl<'de> Deserialize<'de> for Interface {
83	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
84	where
85		D: Deserializer<'de>,
86	{
87		struct InterfaceVisitor;
88
89		impl<'de> Visitor<'de> for InterfaceVisitor {
90			type Value = Interface;
91
92			fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
93				formatter.write_str("an AT-SPI interface name")
94			}
95
96			fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
97			where
98				E: de::Error,
99			{
100				match value {
101					ACCESSIBLE_INTERFACE_NAME => Ok(Interface::Accessible),
102					ACTION_INTERFACE_NAME => Ok(Interface::Action),
103					APPLICATION_INTERFACE_NAME => Ok(Interface::Application),
104					CACHE_INTERFACE_NAME => Ok(Interface::Cache),
105					COLLECTION_INTERFACE_NAME => Ok(Interface::Collection),
106					COMPONENT_INTERFACE_NAME => Ok(Interface::Component),
107					DEVICE_EVENT_CONTROLLER_INTERFACE_NAME => Ok(Interface::DeviceEventController),
108					DEVICE_EVENT_LISTENER_INTERFACE_NAME => Ok(Interface::DeviceEventListener),
109					DOCUMENT_INTERFACE_NAME => Ok(Interface::Document),
110					EDITABLE_TEXT_INTERFACE_NAME => Ok(Interface::EditableText),
111					HYPERLINK_INTERFACE_NAME => Ok(Interface::Hyperlink),
112					HYPERTEXT_INTERFACE_NAME => Ok(Interface::Hypertext),
113					IMAGE_INTERFACE_NAME => Ok(Interface::Image),
114					REGISTRY_INTERFACE_NAME => Ok(Interface::Registry),
115					SELECTION_INTERFACE_NAME => Ok(Interface::Selection),
116					SOCKET_INTERFACE_NAME => Ok(Interface::Socket),
117					TABLE_INTERFACE_NAME => Ok(Interface::Table),
118					TABLE_CELL_INTERFACE_NAME => Ok(Interface::TableCell),
119					TEXT_INTERFACE_NAME => Ok(Interface::Text),
120					VALUE_INTERFACE_NAME => Ok(Interface::Value),
121					_ => Err(de::Error::custom("unknown interface")),
122				}
123			}
124		}
125
126		deserializer.deserialize_identifier(InterfaceVisitor)
127	}
128}
129
130impl Serialize for Interface {
131	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
132	where
133		S: Serializer,
134	{
135		serializer.serialize_str(match self {
136			Interface::Accessible => ACCESSIBLE_INTERFACE_NAME,
137			Interface::Action => ACTION_INTERFACE_NAME,
138			Interface::Application => APPLICATION_INTERFACE_NAME,
139			Interface::Cache => CACHE_INTERFACE_NAME,
140			Interface::Collection => COLLECTION_INTERFACE_NAME,
141			Interface::Component => COMPONENT_INTERFACE_NAME,
142			Interface::DeviceEventController => DEVICE_EVENT_CONTROLLER_INTERFACE_NAME,
143			Interface::DeviceEventListener => DEVICE_EVENT_LISTENER_INTERFACE_NAME,
144			Interface::Document => DOCUMENT_INTERFACE_NAME,
145			Interface::EditableText => EDITABLE_TEXT_INTERFACE_NAME,
146			Interface::Hyperlink => HYPERLINK_INTERFACE_NAME,
147			Interface::Hypertext => HYPERTEXT_INTERFACE_NAME,
148			Interface::Image => IMAGE_INTERFACE_NAME,
149			Interface::Registry => REGISTRY_INTERFACE_NAME,
150			Interface::Selection => SELECTION_INTERFACE_NAME,
151			Interface::Socket => SOCKET_INTERFACE_NAME,
152			Interface::Table => TABLE_INTERFACE_NAME,
153			Interface::TableCell => TABLE_CELL_INTERFACE_NAME,
154			Interface::Text => TEXT_INTERFACE_NAME,
155			Interface::Value => VALUE_INTERFACE_NAME,
156		})
157	}
158}
159
160/// A collection type which encodes the AT-SPI interfaces an accessible object has implemented.
161#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
162pub struct InterfaceSet(BitFlags<Interface>);
163
164impl InterfaceSet {
165	pub fn new<B: Into<BitFlags<Interface>>>(value: B) -> Self {
166		Self(value.into())
167	}
168
169	#[must_use]
170	pub fn empty() -> InterfaceSet {
171		InterfaceSet(Interface::empty())
172	}
173
174	#[must_use]
175	pub fn bits(&self) -> u32 {
176		self.0.bits()
177	}
178
179	#[must_use]
180	pub fn all() -> InterfaceSet {
181		InterfaceSet(Interface::all())
182	}
183
184	pub fn contains<B: Into<BitFlags<Interface>>>(self, other: B) -> bool {
185		self.0.contains(other)
186	}
187
188	pub fn insert<B: Into<BitFlags<Interface>>>(&mut self, other: B) {
189		self.0.insert(other);
190	}
191
192	pub fn iter(self) -> impl Iterator<Item = Interface> {
193		self.0.iter()
194	}
195}
196
197impl<'de> Deserialize<'de> for InterfaceSet {
198	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
199	where
200		D: Deserializer<'de>,
201	{
202		struct InterfaceSetVisitor;
203
204		impl<'de> Visitor<'de> for InterfaceSetVisitor {
205			type Value = InterfaceSet;
206
207			fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
208				formatter.write_str("a sequence comprised of valid AT-SPI interface names")
209			}
210
211			fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
212			where
213				D: Deserializer<'de>,
214			{
215				match <Vec<Interface> as Deserialize>::deserialize(deserializer) {
216					Ok(interfaces) => Ok(InterfaceSet(BitFlags::from_iter(interfaces))),
217					Err(e) => Err(e),
218				}
219			}
220		}
221
222		deserializer.deserialize_newtype_struct("InterfaceSet", InterfaceSetVisitor)
223	}
224}
225
226impl Serialize for InterfaceSet {
227	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
228	where
229		S: Serializer,
230	{
231		serializer
232			.serialize_newtype_struct("InterfaceSet", &self.0.iter().collect::<Vec<Interface>>())
233	}
234}
235
236impl Type for InterfaceSet {
237	fn signature() -> Signature<'static> {
238		<Vec<String> as Type>::signature()
239	}
240}
241
242impl From<Interface> for InterfaceSet {
243	fn from(value: Interface) -> Self {
244		Self(value.into())
245	}
246}
247
248impl std::ops::BitAnd for InterfaceSet {
249	type Output = InterfaceSet;
250
251	fn bitand(self, other: Self) -> Self::Output {
252		InterfaceSet(self.0 & other.0)
253	}
254}
255
256impl std::ops::BitXor for InterfaceSet {
257	type Output = InterfaceSet;
258
259	fn bitxor(self, other: Self) -> Self::Output {
260		InterfaceSet(self.0 ^ other.0)
261	}
262}
263
264impl std::ops::BitOr for InterfaceSet {
265	type Output = InterfaceSet;
266
267	fn bitor(self, other: Self) -> Self::Output {
268		InterfaceSet(self.0 | other.0)
269	}
270}
271
272#[cfg(test)]
273mod tests {
274	use super::*;
275	use byteorder::LE;
276	use zbus::zvariant::{from_slice, to_bytes, EncodingContext as Context};
277
278	#[test]
279	fn serialize_empty_interface_set() {
280		let ctxt = Context::<LE>::new_dbus(0);
281		let encoded = to_bytes(ctxt, &InterfaceSet::empty()).unwrap();
282		assert_eq!(encoded, &[0, 0, 0, 0]);
283	}
284
285	#[test]
286	fn deserialize_empty_interface_set() {
287		let ctxt = Context::<LE>::new_dbus(0);
288		let decoded: InterfaceSet = from_slice(&[0, 0, 0, 0], ctxt).unwrap();
289		assert_eq!(decoded, InterfaceSet::empty());
290	}
291
292	#[test]
293	fn serialize_interface_set_accessible() {
294		let ctxt = Context::<LE>::new_dbus(0);
295		let encoded = to_bytes(ctxt, &InterfaceSet::new(Interface::Accessible)).unwrap();
296		assert_eq!(
297			encoded,
298			&[
299				30, 0, 0, 0, 25, 0, 0, 0, 111, 114, 103, 46, 97, 49, 49, 121, 46, 97, 116, 115,
300				112, 105, 46, 65, 99, 99, 101, 115, 115, 105, 98, 108, 101, 0
301			]
302		);
303	}
304
305	#[test]
306	fn deserialize_interface_set_accessible() {
307		let ctxt = Context::<LE>::new_dbus(0);
308		let decoded: InterfaceSet = from_slice(
309			&[
310				30, 0, 0, 0, 25, 0, 0, 0, 111, 114, 103, 46, 97, 49, 49, 121, 46, 97, 116, 115,
311				112, 105, 46, 65, 99, 99, 101, 115, 115, 105, 98, 108, 101, 0,
312			],
313			ctxt,
314		)
315		.unwrap();
316		assert_eq!(decoded, InterfaceSet::new(Interface::Accessible));
317	}
318
319	#[test]
320	fn can_handle_multiple_interfaces() {
321		let ctxt = Context::<LE>::new_dbus(0);
322		let object =
323			InterfaceSet::new(Interface::Accessible | Interface::Action | Interface::Component);
324		let encoded = to_bytes(ctxt, &object).unwrap();
325		let decoded: InterfaceSet = from_slice(&encoded, ctxt).unwrap();
326		assert!(object == decoded);
327	}
328	#[test]
329	fn match_various_de_serialization_methods() {
330		for iface in InterfaceSet::all().iter() {
331			let displayed = format!("{iface}");
332			let serde_val = serde_plain::to_string(&iface).expect("Unable to serialize {iface}");
333			// this is not *necessary* if Display wants to be implemented for some other reason.
334			// as of when this test is written, it should be the same.
335			// but if you've made a concious decision as a developer that there is a better use for Display, go ahead and remove this
336			assert_eq!(
337				displayed, serde_val,
338				"Serde's serialization does not match the Display trait implementation."
339			);
340			let from_str = Interface::try_from(&*displayed).unwrap();
341			assert_eq!(iface, from_str, "The display trait for {iface} became \"{displayed}\", but was re-serialized as {from_str} via TryFrom<&str>");
342			let serde_from_str: Interface = serde_plain::from_str(&serde_val).unwrap();
343			assert_eq!(serde_from_str, iface, "Serde's deserialization does not match its serialization. {iface} was serialized to \"{serde_val}\", but deserialized into {serde_from_str}");
344		}
345	}
346}
347impl TryFrom<&str> for Interface {
348	type Error = &'static str;
349
350	fn try_from(s: &str) -> Result<Self, Self::Error> {
351		match s {
352			ACCESSIBLE_INTERFACE_NAME => Ok(Interface::Accessible),
353			ACTION_INTERFACE_NAME => Ok(Interface::Action),
354			APPLICATION_INTERFACE_NAME => Ok(Interface::Application),
355			COLLECTION_INTERFACE_NAME => Ok(Interface::Collection),
356			COMPONENT_INTERFACE_NAME => Ok(Interface::Component),
357			DOCUMENT_INTERFACE_NAME => Ok(Interface::Document),
358			HYPERTEXT_INTERFACE_NAME => Ok(Interface::Hypertext),
359			HYPERLINK_INTERFACE_NAME => Ok(Interface::Hyperlink),
360			IMAGE_INTERFACE_NAME => Ok(Interface::Image),
361			SELECTION_INTERFACE_NAME => Ok(Interface::Selection),
362			SOCKET_INTERFACE_NAME => Ok(Interface::Socket),
363			TABLE_INTERFACE_NAME => Ok(Interface::Table),
364			TABLE_CELL_INTERFACE_NAME => Ok(Interface::TableCell),
365			TEXT_INTERFACE_NAME => Ok(Interface::Text),
366			EDITABLE_TEXT_INTERFACE_NAME => Ok(Interface::EditableText),
367			CACHE_INTERFACE_NAME => Ok(Interface::Cache),
368			VALUE_INTERFACE_NAME => Ok(Interface::Value),
369			REGISTRY_INTERFACE_NAME => Ok(Interface::Registry),
370			DEVICE_EVENT_CONTROLLER_INTERFACE_NAME => Ok(Interface::DeviceEventController),
371			DEVICE_EVENT_LISTENER_INTERFACE_NAME => Ok(Interface::DeviceEventListener),
372			_ => Err("No interface found for conversion."),
373		}
374	}
375}
376impl std::fmt::Display for Interface {
377	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
378		let interface_string = match self {
379			Interface::Accessible => ACCESSIBLE_INTERFACE_NAME,
380			Interface::Action => ACTION_INTERFACE_NAME,
381			Interface::Application => APPLICATION_INTERFACE_NAME,
382			Interface::Cache => CACHE_INTERFACE_NAME,
383			Interface::Collection => COLLECTION_INTERFACE_NAME,
384			Interface::Component => COMPONENT_INTERFACE_NAME,
385			Interface::DeviceEventController => DEVICE_EVENT_CONTROLLER_INTERFACE_NAME,
386			Interface::DeviceEventListener => DEVICE_EVENT_LISTENER_INTERFACE_NAME,
387			Interface::Document => DOCUMENT_INTERFACE_NAME,
388			Interface::EditableText => EDITABLE_TEXT_INTERFACE_NAME,
389			Interface::Hypertext => HYPERTEXT_INTERFACE_NAME,
390			Interface::Hyperlink => HYPERLINK_INTERFACE_NAME,
391			Interface::Image => IMAGE_INTERFACE_NAME,
392			Interface::Registry => REGISTRY_INTERFACE_NAME,
393			Interface::Socket => SOCKET_INTERFACE_NAME,
394			Interface::Selection => SELECTION_INTERFACE_NAME,
395			Interface::Table => TABLE_INTERFACE_NAME,
396			Interface::TableCell => TABLE_CELL_INTERFACE_NAME,
397			Interface::Text => TEXT_INTERFACE_NAME,
398			Interface::Value => VALUE_INTERFACE_NAME,
399		}
400		.to_string();
401		write!(f, "{interface_string}")
402	}
403}