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 | |
6 | use enumflags2::{bitflags , BitFlag, BitFlags}; |
7 | use serde::{ |
8 | de::{self, Deserialize, Deserializer, Visitor}, |
9 | ser::{Serialize, Serializer}, |
10 | }; |
11 | use std::fmt; |
12 | use zvariant::{Signature, Type}; |
13 | |
14 | const ACCESSIBLE_INTERFACE_NAME: &str = "org.a11y.atspi.Accessible" ; |
15 | const ACTION_INTERFACE_NAME: &str = "org.a11y.atspi.Action" ; |
16 | const APPLICATION_INTERFACE_NAME: &str = "org.a11y.atspi.Application" ; |
17 | const CACHE_INTERFACE_NAME: &str = "org.a11y.atspi.Cache" ; |
18 | const COLLECTION_INTERFACE_NAME: &str = "org.a11y.atspi.Collection" ; |
19 | const COMPONENT_INTERFACE_NAME: &str = "org.a11y.atspi.Component" ; |
20 | const DOCUMENT_INTERFACE_NAME: &str = "org.a11y.atspi.Document" ; |
21 | const DEVICE_EVENT_CONTROLLER_INTERFACE_NAME: &str = "org.a11y.atspi.DeviceEventController" ; |
22 | const DEVICE_EVENT_LISTENER_INTERFACE_NAME: &str = "org.a11y.atspi.DeviceEventListener" ; |
23 | const EDITABLE_TEXT_INTERFACE_NAME: &str = "org.a11y.atspi.EditableText" ; |
24 | const HYPERLINK_INTERFACE_NAME: &str = "org.a11y.atspi.Hyperlink" ; |
25 | const HYPERTEXT_INTERFACE_NAME: &str = "org.a11y.atspi.Hypertext" ; |
26 | const IMAGE_INTERFACE_NAME: &str = "org.a11y.atspi.Image" ; |
27 | const REGISTRY_INTERFACE_NAME: &str = "org.a11y.atspi.Registry" ; |
28 | const SELECTION_INTERFACE_NAME: &str = "org.a11y.atspi.Selection" ; |
29 | const SOCKET_INTERFACE_NAME: &str = "org.a11y.atspi.Socket" ; |
30 | const TABLE_INTERFACE_NAME: &str = "org.a11y.atspi.Table" ; |
31 | const TABLE_CELL_INTERFACE_NAME: &str = "org.a11y.atspi.TableCell" ; |
32 | const TEXT_INTERFACE_NAME: &str = "org.a11y.atspi.Text" ; |
33 | const 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)] |
39 | pub 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 | |
82 | impl<'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 | |
130 | impl 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)] |
162 | pub struct InterfaceSet(BitFlags<Interface>); |
163 | |
164 | impl 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 | |
197 | impl<'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 | |
226 | impl 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 | |
236 | impl Type for InterfaceSet { |
237 | fn signature() -> Signature<'static> { |
238 | <Vec<String> as Type>::signature() |
239 | } |
240 | } |
241 | |
242 | impl From<Interface> for InterfaceSet { |
243 | fn from(value: Interface) -> Self { |
244 | Self(value.into()) |
245 | } |
246 | } |
247 | |
248 | impl 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 | |
256 | impl 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 | |
264 | impl 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)] |
273 | mod 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 | } |
347 | impl 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 | } |
376 | impl 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 | |