ferroui_base/input/
async_data_transfer_extensions.rs1use super::async_to_sync_data_transfer::AsyncToSyncDataTransfer;
2use super::platform::ClipboardError;
3use super::sync_to_async_data_transfer::SyncToAsyncDataTransfer;
4use super::{
5 AsyncDataTransferItemExtensions, DataFormat, DataFormatOf, IAsyncDataTransfer, IAsyncDataTransferItem,
6 IDataTransfer, LocalBoxFuture,
7};
8use crate::logging::{LogEventLevel, Logger};
9use crate::media::imaging::Bitmap;
10use crate::platform::storage::IStorageItem;
11use std::rc::Rc;
12
13pub struct AsyncDataTransferItems {
16 items: Rc<[Rc<dyn IAsyncDataTransferItem>]>,
17 format: DataFormat,
18 index: usize,
19}
20
21impl Iterator for AsyncDataTransferItems {
22 type Item = Rc<dyn IAsyncDataTransferItem>;
23
24 fn next(&mut self) -> Option<Self::Item> {
25 while let Some(item) = self.items.get(self.index) {
26 self.index += 1;
27 if item.contains(&self.format) {
28 return Some(item.clone());
29 }
30 }
31 None
32 }
33}
34
35impl dyn IAsyncDataTransfer {
36 pub fn to_synchronous(self: Rc<Self>, log_area: &'static str) -> Rc<dyn IDataTransfer> {
42 if let Some(data_transfer) = self.clone().as_data_transfer() {
43 return data_transfer;
44 }
45
46 if let Some(logger) = Logger::try_get(LogEventLevel::Warning, log_area) {
47 logger.log(
48 None,
49 "Using a synchronous wrapper for IAsyncDataTransferItem. Consider implementing IDataTransfer instead.",
50 );
51 }
52
53 AsyncToSyncDataTransfer::new(self)
54 }
55}
56
57impl dyn IDataTransfer {
58 pub fn to_asynchronous(self: Rc<Self>) -> Rc<dyn IAsyncDataTransfer> {
63 match self.clone().as_async_data_transfer() {
64 Some(data_transfer) => data_transfer,
65 None => SyncToAsyncDataTransfer::new(self),
66 }
67 }
68}
69
70pub trait AsyncDataTransferExtensions: IAsyncDataTransfer {
75 fn contains(&self, format: &DataFormat) -> bool {
77 self.formats().iter().any(|candidate| candidate == format)
78 }
79
80 fn get_items(&self, format: &DataFormat) -> AsyncDataTransferItems {
86 AsyncDataTransferItems { items: self.items(), format: format.clone(), index: 0 }
87 }
88
89 fn try_get_value_async<T: Clone + 'static>(
97 &self,
98 format: &DataFormatOf<T>,
99 ) -> LocalBoxFuture<Result<Option<T>, ClipboardError>> {
100 let item = self.try_items().and_then(|items| {
104 for item in items.iter() {
105 if item.try_contains(format)? {
106 return Ok(Some(item.clone()));
107 }
108 }
109 Ok(None)
110 });
111
112 match item {
113 Ok(Some(item)) => item.try_get_value_async(format),
114 Ok(None) => Box::pin(std::future::ready(Ok(None))),
115 Err(error) => Box::pin(std::future::ready(Err(error))),
116 }
117 }
118
119 fn try_get_values_async<T: Clone + 'static>(
124 &self,
125 format: &DataFormatOf<T>,
126 ) -> LocalBoxFuture<Result<Option<Vec<T>>, ClipboardError>> {
127 let items = self.try_items();
128 let format = format.clone();
129
130 Box::pin(async move {
131 let mut results: Option<Vec<T>> = None;
132
133 for item in items?.iter() {
137 if !item.try_contains(&format)? {
138 continue;
139 }
140
141 let Some(result) = item.try_get_value_async(&format).await? else { continue };
142 results.get_or_insert_with(Vec::new).push(result);
143 }
144
145 Ok(results)
146 })
147 }
148
149 fn try_get_text_async(&self) -> LocalBoxFuture<Result<Option<String>, ClipboardError>> {
154 self.try_get_value_async(&DataFormat::text())
155 }
156
157 fn try_get_bitmap_async(&self) -> LocalBoxFuture<Result<Option<Rc<Bitmap>>, ClipboardError>> {
162 self.try_get_value_async(&DataFormat::bitmap())
163 }
164
165 fn try_get_file_async(&self) -> LocalBoxFuture<Result<Option<Rc<dyn IStorageItem>>, ClipboardError>> {
169 self.try_get_value_async(&DataFormat::file())
170 }
171
172 fn try_get_files_async(&self) -> LocalBoxFuture<Result<Option<Vec<Rc<dyn IStorageItem>>>, ClipboardError>> {
177 self.try_get_values_async(&DataFormat::file())
178 }
179}
180
181impl<I: IAsyncDataTransfer + ?Sized> AsyncDataTransferExtensions for I {}