ferroui_base/input/platform/
platform_data_transfer_item.rs1use super::ClipboardError;
2use crate::input::{DataFormat, DataFormatOf, IAsyncDataTransferItem, IDataTransferItem, LocalBoxFuture};
3use std::any::Any;
4use std::cell::RefCell;
5use std::rc::Rc;
6
7pub trait PlatformDataTransferItemImpl {
10 fn provide_formats(&self) -> Result<Vec<DataFormat>, ClipboardError>;
13
14 fn try_get_raw_core(&self, format: &DataFormat) -> Result<Option<Rc<dyn Any>>, ClipboardError>;
16}
17
18struct SingleFormatItem {
19 format: DataFormat,
20 value: Rc<dyn Any>,
21}
22
23impl PlatformDataTransferItemImpl for SingleFormatItem {
24 fn provide_formats(&self) -> Result<Vec<DataFormat>, ClipboardError> {
25 Ok(vec![self.format.clone()])
26 }
27
28 fn try_get_raw_core(&self, format: &DataFormat) -> Result<Option<Rc<dyn Any>>, ClipboardError> {
29 if self.format == *format {
30 Ok(Some(self.value.clone()))
31 } else {
32 Ok(None)
33 }
34 }
35}
36
37pub struct PlatformDataTransferItem {
41 formats: RefCell<Option<Rc<[DataFormat]>>>,
42 platform_impl: Box<dyn PlatformDataTransferItemImpl>,
43}
44
45impl PlatformDataTransferItem {
46 pub fn new(platform_impl: impl PlatformDataTransferItemImpl + 'static) -> Rc<PlatformDataTransferItem> {
48 Rc::new(PlatformDataTransferItem { formats: RefCell::new(None), platform_impl: Box::new(platform_impl) })
49 }
50
51 pub fn create<T: 'static>(format: &DataFormatOf<T>, value: T) -> Rc<PlatformDataTransferItem> {
53 Self::new(SingleFormatItem { format: format.as_data_format().clone(), value: Rc::new(value) })
54 }
55
56 #[track_caller]
63 pub fn formats(&self) -> Rc<[DataFormat]> {
64 match self.try_formats() {
65 Ok(formats) => formats,
66 Err(error) => panic!("{error}"),
67 }
68 }
69
70 pub fn try_formats(&self) -> Result<Rc<[DataFormat]>, ClipboardError> {
73 if let Some(formats) = self.formats.borrow().as_ref() {
74 return Ok(formats.clone());
75 }
76
77 let formats: Rc<[DataFormat]> = Rc::from(self.platform_impl.provide_formats()?);
78 *self.formats.borrow_mut() = Some(formats.clone());
79 Ok(formats)
80 }
81
82 #[track_caller]
84 pub fn contains(&self, format: &DataFormat) -> bool {
85 self.formats().iter().any(|candidate| candidate == format)
86 }
87
88 #[track_caller]
97 pub fn try_get_raw(&self, format: &DataFormat) -> Option<Rc<dyn Any>> {
98 match self.try_get_raw_result(format) {
99 Ok(value) => value,
100 Err(error) => panic!("{error}"),
101 }
102 }
103
104 pub fn try_get_raw_result(&self, format: &DataFormat) -> Result<Option<Rc<dyn Any>>, ClipboardError> {
108 if self.try_formats()?.iter().any(|candidate| candidate == format) {
109 self.platform_impl.try_get_raw_core(format)
110 } else {
111 Ok(None)
112 }
113 }
114}
115
116impl IDataTransferItem for PlatformDataTransferItem {
117 fn formats(&self) -> Rc<[DataFormat]> {
118 PlatformDataTransferItem::formats(self)
119 }
120
121 fn try_get_raw(&self, format: &DataFormat) -> Option<Rc<dyn Any>> {
122 PlatformDataTransferItem::try_get_raw(self, format)
123 }
124}
125
126impl IAsyncDataTransferItem for PlatformDataTransferItem {
127 fn formats(&self) -> Rc<[DataFormat]> {
128 PlatformDataTransferItem::formats(self)
129 }
130
131 fn try_formats(&self) -> Result<Rc<[DataFormat]>, ClipboardError> {
132 PlatformDataTransferItem::try_formats(self)
133 }
134
135 fn try_get_raw_async(&self, format: &DataFormat) -> LocalBoxFuture<Result<Option<Rc<dyn Any>>, ClipboardError>> {
136 Box::pin(std::future::ready(PlatformDataTransferItem::try_get_raw_result(self, format)))
137 }
138}