atspi_client/
convertable.rs

1use async_trait::async_trait;
2use atspi_proxies::{
3	accessible::{Accessible, AccessibleBlocking, AccessibleProxy, AccessibleProxyBlocking},
4	action::{Action, ActionBlocking, ActionProxy, ActionProxyBlocking},
5	application::{Application, ApplicationBlocking, ApplicationProxy, ApplicationProxyBlocking},
6	collection::{Collection, CollectionBlocking, CollectionProxy, CollectionProxyBlocking},
7	component::{Component, ComponentBlocking, ComponentProxy, ComponentProxyBlocking},
8	document::{Document, DocumentBlocking, DocumentProxy, DocumentProxyBlocking},
9	editable_text::{
10		EditableText, EditableTextBlocking, EditableTextProxy, EditableTextProxyBlocking,
11	},
12	hyperlink::{Hyperlink, HyperlinkBlocking, HyperlinkProxy, HyperlinkProxyBlocking},
13	hypertext::{Hypertext, HypertextBlocking, HypertextProxy, HypertextProxyBlocking},
14	image::{Image, ImageBlocking, ImageProxy, ImageProxyBlocking},
15	selection::{Selection, SelectionBlocking, SelectionProxy, SelectionProxyBlocking},
16	table::{Table, TableBlocking, TableProxy, TableProxyBlocking},
17	table_cell::{TableCell, TableCellBlocking, TableCellProxy, TableCellProxyBlocking},
18	text::{Text, TextBlocking, TextProxy, TextProxyBlocking},
19	value::{Value, ValueBlocking, ValueProxy, ValueProxyBlocking},
20	AtspiProxy,
21};
22use std::ops::Deref;
23use zbus::{
24	blocking::Proxy as ProxyBlocking, blocking::ProxyBuilder as ProxyBuilderBlocking,
25	CacheProperties, Error, Proxy, ProxyBuilder, ProxyDefault,
26};
27
28#[allow(clippy::module_name_repetitions)]
29#[async_trait]
30pub trait Convertable {
31	type Error: std::error::Error;
32	type Accessible: Accessible + Send + Sync;
33	type Action: Action + Send + Sync;
34	type Application: Application + Send + Sync;
35	type Collection: Collection + Send + Sync;
36	type Component: Component + Send + Sync;
37	type Document: Document + Send + Sync;
38	type Hypertext: Hypertext + Send + Sync;
39	type Hyperlink: Hyperlink + Send + Sync;
40	type Image: Image + Send + Sync;
41	type Selection: Selection + Send + Sync;
42	type Table: Table + Send + Sync;
43	type TableCell: TableCell + Send + Sync;
44	type Text: Text + Send + Sync;
45	type EditableText: EditableText + Send + Sync;
46	type Value: Value + Send + Sync;
47
48	/// Creates an [`Self::Accessible`] from the existing accessible item.
49	/// # Errors
50	///
51	/// This may fail based on the implementation of.
52	/// Generally, it fails if the accessible item does not implement to accessible interface.
53	/// This shouldn't be possible, but this function may fail for other reasons.
54	/// For example, to convert a [`zbus::Proxy`] into a [`Self::Accessible`], it may fail to create the new [`atspi_proxies::accessible::AccessibleProxy`].
55	async fn to_accessible(&self) -> Result<Self::Accessible, Self::Error>;
56	/// Creates an [`Self::Action`] from the existing accessible item.
57	/// # Errors
58	///
59	/// This may fail based on the implementation.
60	/// Generally, it fails if the accessible item does not implement to action interface.
61	async fn to_action(&self) -> Result<Self::Action, Self::Error>;
62	/// Creates an [`Self::Application`] from the existing accessible item.
63	/// # Errors
64	///
65	/// This may fail based on the implementation.
66	/// Generally, it fails if the accessible item does not implement to application interface.
67	async fn to_application(&self) -> Result<Self::Application, Self::Error>;
68	/// Creates an [`Self::Collection`] from the existing accessible item.
69	/// # Errors
70	///
71	/// This may fail based on the implementation.
72	/// Generally, it fails if the accessible item does not implement to collection interface.
73	async fn to_collection(&self) -> Result<Self::Collection, Self::Error>;
74	/// Creates an [`Self::Component`] from the existing accessible item.
75	/// # Errors
76	///
77	/// This may fail based on the implementation.
78	/// Generally, it fails if the accessible item does not implement to component interface.
79	async fn to_component(&self) -> Result<Self::Component, Self::Error>;
80	async fn to_document(&self) -> Result<Self::Document, Self::Error>;
81	async fn to_hypertext(&self) -> Result<Self::Hypertext, Self::Error>;
82	async fn to_hyperlink(&self) -> Result<Self::Hyperlink, Self::Error>;
83	async fn to_image(&self) -> Result<Self::Image, Self::Error>;
84	async fn to_selection(&self) -> Result<Self::Selection, Self::Error>;
85	async fn to_table(&self) -> Result<Self::Table, Self::Error>;
86	async fn to_table_cell(&self) -> Result<Self::TableCell, Self::Error>;
87	async fn to_text(&self) -> Result<Self::Text, Self::Error>;
88	async fn to_editable_text(&self) -> Result<Self::EditableText, Self::Error>;
89	async fn to_value(&self) -> Result<Self::Value, Self::Error>;
90}
91
92#[allow(clippy::module_name_repetitions)]
93pub trait ConvertableBlocking {
94	type Error: std::error::Error;
95	type Accessible: AccessibleBlocking;
96	type Action: ActionBlocking;
97	type Application: ApplicationBlocking;
98	type Collection: CollectionBlocking;
99	type Component: ComponentBlocking;
100	type Document: DocumentBlocking;
101	type Hypertext: HypertextBlocking;
102	type Hyperlink: HyperlinkBlocking;
103	type Image: ImageBlocking;
104	type Selection: SelectionBlocking;
105	type Table: TableBlocking;
106	type TableCell: TableCellBlocking;
107	type Text: TextBlocking;
108	type EditableText: EditableTextBlocking;
109	type Value: ValueBlocking;
110
111	/// Creates an [`Self::Accessible`] from the existing accessible item.
112	/// # Errors
113	///
114	/// This may fail based on the implementation of.
115	/// Generally, it fails if the accessible item does not implement to accessible interface.
116	/// This shouldn't be possible, but this function may fail for other reasons.
117	/// For example, to convert a [`zbus::Proxy`] into a [`Self::Accessible`], it may fail to create the new [`atspi_proxies::accessible::AccessibleProxyBlocking`].
118	fn to_accessible(&self) -> Result<Self::Accessible, Self::Error>;
119	/// Creates an [`Self::Action`] from the existing accessible item.
120	/// # Errors
121	///
122	/// This may fail based on the implementation.
123	/// Generally, it fails if the accessible item does not implement to action interface.
124	fn to_action(&self) -> Result<Self::Action, Self::Error>;
125	/// Creates an [`Self::Application`] from the existing accessible item.
126	/// # Errors
127	///
128	/// This may fail based on the implementation.
129	/// Generally, it fails if the accessible item does not implement to application interface.
130	fn to_application(&self) -> Result<Self::Application, Self::Error>;
131	/// Creates an [`Self::Collection`] from the existing accessible item.
132	/// # Errors
133	///
134	/// This may fail based on the implementation.
135	/// Generally, it fails if the accessible item does not implement to collection interface.
136	fn to_collection(&self) -> Result<Self::Collection, Self::Error>;
137	/// Creates an [`Self::Component`] from the existing accessible item.
138	/// # Errors
139	///
140	/// This may fail based on the implementation.
141	/// Generally, it fails if the accessible item does not implement to component interface.
142	fn to_component(&self) -> Result<Self::Component, Self::Error>;
143	/// Creates an [`Self::Document`] from the existing accessible item.
144	/// # Errors
145	///
146	/// This may fail based on the implementation.
147	/// Generally, it fails if the accessible item does not implement to document interface.
148	fn to_document(&self) -> Result<Self::Document, Self::Error>;
149	/// Creates an [`Self::Hypertext`] from the existing accessible item.
150	/// # Errors
151	///
152	/// This may fail based on the implementation.
153	/// Generally, it fails if the accessible item does not implement to hypertext interface.
154	fn to_hypertext(&self) -> Result<Self::Hypertext, Self::Error>;
155	/// Creates an [`Self::Hyperlink`] from the existing accessible item.
156	/// # Errors
157	///
158	/// This may fail based on the implementation.
159	/// Generally, it fails if the accessible item does not implement to hyperlink interface.
160	fn to_hyperlink(&self) -> Result<Self::Hyperlink, Self::Error>;
161	/// Creates an [`Self::Image`] from the existing accessible item.
162	/// # Errors
163	///
164	/// This may fail based on the implementation.
165	/// Generally, it fails if the accessible item does not implement to image interface.
166	fn to_image(&self) -> Result<Self::Image, Self::Error>;
167	/// Creates an [`Self::Selection`] from the existing accessible item.
168	/// # Errors
169	///
170	/// This may fail based on the implementation.
171	/// Generally, it fails if the accessible item does not implement to selection interface.
172	fn to_selection(&self) -> Result<Self::Selection, Self::Error>;
173	/// Creates an [`Self::Table`] from the existing accessible item.
174	/// # Errors
175	///
176	/// This may fail based on the implementation.
177	/// Generally, it fails if the accessible item does not implement to table interface.
178	fn to_table(&self) -> Result<Self::Table, Self::Error>;
179	/// Creates an [`Self::TableCell`] from the existing accessible item.
180	/// # Errors
181	///
182	/// This may fail based on the implementation.
183	/// Generally, it fails if the accessible item does not implement to table cell interface.
184	fn to_table_cell(&self) -> Result<Self::TableCell, Self::Error>;
185	/// Creates an [`Self::Text`] from the existing accessible item.
186	/// # Errors
187	///
188	/// This may fail based on the implementation.
189	/// Generally, it fails if the accessible item does not implement to text interface.
190	fn to_text(&self) -> Result<Self::Text, Self::Error>;
191	/// Creates an [`Self::EditableText`] from the existing accessible item.
192	/// # Errors
193	///
194	/// This may fail based on the implementation.
195	/// Generally, it fails if the accessible item does not implement to editable text interface.
196	fn to_editable_text(&self) -> Result<Self::EditableText, Self::Error>;
197	/// Creates an [`Self::Value`] from the existing accessible item.
198	/// # Errors
199	///
200	/// This may fail based on the implementation.
201	/// Generally, it fails if the accessible item does not implement to value interface.
202	fn to_value(&self) -> Result<Self::Value, Self::Error>;
203}
204
205#[inline]
206async fn convert_to_new_type<
207	'a,
208	'b,
209	T: From<Proxy<'b>> + ProxyDefault + AtspiProxy,
210	U: Deref<Target = Proxy<'a>> + ProxyDefault + AtspiProxy,
211>(
212	from: &U,
213) -> zbus::Result<T> {
214	// first thing is first, we need to creat an accessible to query the interfaces.
215	let accessible = AccessibleProxy::builder(from.connection())
216		.destination(from.destination())?
217		.cache_properties(CacheProperties::No)
218		.path(from.path())?
219		.build()
220		.await?;
221	// if the interface we're trying to convert to is not available as an interface; this can be problematic because the interface we're passing in could potentially be different from what we're converting to.
222	if !accessible
223		.get_interfaces()
224		.await?
225		.contains(<T as AtspiProxy>::INTERFACE)
226	{
227		return Err(Error::InterfaceNotFound);
228	}
229	// otherwise, make a new Proxy with the related type.
230	let path = from.path().to_owned();
231	let dest = from.destination().to_owned();
232	ProxyBuilder::<'b, T>::new_bare(from.connection())
233		.interface(<T as ProxyDefault>::INTERFACE)?
234		.destination(dest)?
235		.cache_properties(CacheProperties::No)
236		.path(path)?
237		.build()
238		.await
239}
240
241#[inline]
242fn convert_to_new_type_blocking<
243	'a,
244	'b,
245	T: From<Proxy<'b>> + ProxyDefault + AtspiProxy,
246	U: Deref<Target = ProxyBlocking<'a>> + ProxyDefault,
247>(
248	from: &U,
249) -> zbus::Result<T> {
250	// first thing is first, we need to creat an accessible to query the interfaces.
251	let accessible = AccessibleProxyBlocking::builder(from.connection())
252		.destination(from.destination())?
253		.cache_properties(CacheProperties::No)
254		.path(from.path())?
255		.build()?;
256	// if the interface we're trying to convert to is not available as an interface; this can be problematic because the interface we're passing in could potentially be different from what we're converting to.
257	if !accessible.get_interfaces()?.contains(<T as AtspiProxy>::INTERFACE) {
258		return Err(Error::InterfaceNotFound);
259	}
260	// otherwise, make a new Proxy with the related type.
261	let path = from.path().to_owned();
262	let dest = from.destination().to_owned();
263	ProxyBuilderBlocking::<'b, T>::new_bare(from.connection())
264		.interface(<T as ProxyDefault>::INTERFACE)?
265		.destination(dest)?
266		.cache_properties(CacheProperties::No)
267		.path(path)?
268		.build()
269}
270
271#[async_trait]
272impl<'a, T: Deref<Target = Proxy<'a>> + ProxyDefault + AtspiProxy + Sync> Convertable for T {
273	type Error = zbus::Error;
274	type Accessible = AccessibleProxy<'a>;
275	type Action = ActionProxy<'a>;
276	type Application = ApplicationProxy<'a>;
277	type Collection = CollectionProxy<'a>;
278	type Component = ComponentProxy<'a>;
279	type Document = DocumentProxy<'a>;
280	type Hypertext = HypertextProxy<'a>;
281	type Hyperlink = HyperlinkProxy<'a>;
282	type Image = ImageProxy<'a>;
283	type Selection = SelectionProxy<'a>;
284	type Table = TableProxy<'a>;
285	type TableCell = TableCellProxy<'a>;
286	type Text = TextProxy<'a>;
287	type EditableText = EditableTextProxy<'a>;
288	type Value = ValueProxy<'a>;
289	/* no guard due to assumption it is always possible */
290	async fn to_accessible(&self) -> zbus::Result<Self::Accessible> {
291		convert_to_new_type(self).await
292	}
293	async fn to_action(&self) -> zbus::Result<Self::Action> {
294		convert_to_new_type(self).await
295	}
296	async fn to_application(&self) -> zbus::Result<Self::Application> {
297		convert_to_new_type(self).await
298	}
299	async fn to_collection(&self) -> zbus::Result<Self::Collection> {
300		convert_to_new_type(self).await
301	}
302	async fn to_component(&self) -> zbus::Result<Self::Component> {
303		convert_to_new_type(self).await
304	}
305	async fn to_document(&self) -> zbus::Result<Self::Document> {
306		convert_to_new_type(self).await
307	}
308	async fn to_hypertext(&self) -> zbus::Result<Self::Hypertext> {
309		convert_to_new_type(self).await
310	}
311	async fn to_hyperlink(&self) -> zbus::Result<Self::Hyperlink> {
312		convert_to_new_type(self).await
313	}
314	async fn to_image(&self) -> zbus::Result<Self::Image> {
315		convert_to_new_type(self).await
316	}
317	async fn to_selection(&self) -> zbus::Result<Self::Selection> {
318		convert_to_new_type(self).await
319	}
320	async fn to_table(&self) -> zbus::Result<Self::Table> {
321		convert_to_new_type(self).await
322	}
323	async fn to_table_cell(&self) -> zbus::Result<Self::TableCell> {
324		convert_to_new_type(self).await
325	}
326	async fn to_text(&self) -> zbus::Result<Self::Text> {
327		convert_to_new_type(self).await
328	}
329	async fn to_editable_text(&self) -> zbus::Result<Self::EditableText> {
330		convert_to_new_type(self).await
331	}
332	async fn to_value(&self) -> zbus::Result<Self::Value> {
333		convert_to_new_type(self).await
334	}
335}
336
337impl<'a, T: Deref<Target = ProxyBlocking<'a>> + ProxyDefault + AtspiProxy> ConvertableBlocking
338	for T
339{
340	type Error = zbus::Error;
341	type Accessible = AccessibleProxyBlocking<'a>;
342	type Action = ActionProxyBlocking<'a>;
343	type Application = ApplicationProxyBlocking<'a>;
344	type Collection = CollectionProxyBlocking<'a>;
345	type Component = ComponentProxyBlocking<'a>;
346	type Document = DocumentProxyBlocking<'a>;
347	type Hypertext = HypertextProxyBlocking<'a>;
348	type Hyperlink = HyperlinkProxyBlocking<'a>;
349	type Image = ImageProxyBlocking<'a>;
350	type Selection = SelectionProxyBlocking<'a>;
351	type Table = TableProxyBlocking<'a>;
352	type TableCell = TableCellProxyBlocking<'a>;
353	type Text = TextProxyBlocking<'a>;
354	type EditableText = EditableTextProxyBlocking<'a>;
355	type Value = ValueProxyBlocking<'a>;
356	/* no guard due to assumption it is always possible */
357	fn to_accessible(&self) -> zbus::Result<Self::Accessible> {
358		convert_to_new_type_blocking(self)
359	}
360	fn to_action(&self) -> zbus::Result<Self::Action> {
361		convert_to_new_type_blocking(self)
362	}
363	fn to_application(&self) -> zbus::Result<Self::Application> {
364		convert_to_new_type_blocking(self)
365	}
366	fn to_collection(&self) -> zbus::Result<Self::Collection> {
367		convert_to_new_type_blocking(self)
368	}
369	fn to_component(&self) -> zbus::Result<Self::Component> {
370		convert_to_new_type_blocking(self)
371	}
372	fn to_document(&self) -> zbus::Result<Self::Document> {
373		convert_to_new_type_blocking(self)
374	}
375	fn to_hypertext(&self) -> zbus::Result<Self::Hypertext> {
376		convert_to_new_type_blocking(self)
377	}
378	fn to_hyperlink(&self) -> zbus::Result<Self::Hyperlink> {
379		convert_to_new_type_blocking(self)
380	}
381	fn to_image(&self) -> zbus::Result<Self::Image> {
382		convert_to_new_type_blocking(self)
383	}
384	fn to_selection(&self) -> zbus::Result<Self::Selection> {
385		convert_to_new_type_blocking(self)
386	}
387	fn to_table(&self) -> zbus::Result<Self::Table> {
388		convert_to_new_type_blocking(self)
389	}
390	fn to_table_cell(&self) -> zbus::Result<Self::TableCell> {
391		convert_to_new_type_blocking(self)
392	}
393	fn to_text(&self) -> zbus::Result<Self::Text> {
394		convert_to_new_type_blocking(self)
395	}
396	fn to_editable_text(&self) -> zbus::Result<Self::EditableText> {
397		convert_to_new_type_blocking(self)
398	}
399	fn to_value(&self) -> zbus::Result<Self::Value> {
400		convert_to_new_type_blocking(self)
401	}
402}