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(name:"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}
404