use super::ClipboardError;
use crate::input::{DataFormat, DataFormatOf, IAsyncDataTransferItem, IDataTransferItem, LocalBoxFuture};
use std::any::Any;
use std::cell::RefCell;
use std::rc::Rc;
pub trait PlatformDataTransferItemImpl {
fn provide_formats(&self) -> Result<Vec<DataFormat>, ClipboardError>;
fn try_get_raw_core(&self, format: &DataFormat) -> Result<Option<Rc<dyn Any>>, ClipboardError>;
}
struct SingleFormatItem {
format: DataFormat,
value: Rc<dyn Any>,
}
impl PlatformDataTransferItemImpl for SingleFormatItem {
fn provide_formats(&self) -> Result<Vec<DataFormat>, ClipboardError> {
Ok(vec![self.format.clone()])
}
fn try_get_raw_core(&self, format: &DataFormat) -> Result<Option<Rc<dyn Any>>, ClipboardError> {
if self.format == *format {
Ok(Some(self.value.clone()))
} else {
Ok(None)
}
}
}
pub struct PlatformDataTransferItem {
formats: RefCell<Option<Rc<[DataFormat]>>>,
platform_impl: Box<dyn PlatformDataTransferItemImpl>,
}
impl PlatformDataTransferItem {
pub fn new(platform_impl: impl PlatformDataTransferItemImpl + 'static) -> Rc<PlatformDataTransferItem> {
Rc::new(PlatformDataTransferItem { formats: RefCell::new(None), platform_impl: Box::new(platform_impl) })
}
pub fn create<T: 'static>(format: &DataFormatOf<T>, value: T) -> Rc<PlatformDataTransferItem> {
Self::new(SingleFormatItem { format: format.as_data_format().clone(), value: Rc::new(value) })
}
#[track_caller]
pub fn formats(&self) -> Rc<[DataFormat]> {
match self.try_formats() {
Ok(formats) => formats,
Err(error) => panic!("{error}"),
}
}
pub fn try_formats(&self) -> Result<Rc<[DataFormat]>, ClipboardError> {
if let Some(formats) = self.formats.borrow().as_ref() {
return Ok(formats.clone());
}
let formats: Rc<[DataFormat]> = Rc::from(self.platform_impl.provide_formats()?);
*self.formats.borrow_mut() = Some(formats.clone());
Ok(formats)
}
#[track_caller]
pub fn contains(&self, format: &DataFormat) -> bool {
self.formats().iter().any(|candidate| candidate == format)
}
#[track_caller]
pub fn try_get_raw(&self, format: &DataFormat) -> Option<Rc<dyn Any>> {
match self.try_get_raw_result(format) {
Ok(value) => value,
Err(error) => panic!("{error}"),
}
}
pub fn try_get_raw_result(&self, format: &DataFormat) -> Result<Option<Rc<dyn Any>>, ClipboardError> {
if self.try_formats()?.iter().any(|candidate| candidate == format) {
self.platform_impl.try_get_raw_core(format)
} else {
Ok(None)
}
}
}
impl IDataTransferItem for PlatformDataTransferItem {
fn formats(&self) -> Rc<[DataFormat]> {
PlatformDataTransferItem::formats(self)
}
fn try_get_raw(&self, format: &DataFormat) -> Option<Rc<dyn Any>> {
PlatformDataTransferItem::try_get_raw(self, format)
}
}
impl IAsyncDataTransferItem for PlatformDataTransferItem {
fn formats(&self) -> Rc<[DataFormat]> {
PlatformDataTransferItem::formats(self)
}
fn try_formats(&self) -> Result<Rc<[DataFormat]>, ClipboardError> {
PlatformDataTransferItem::try_formats(self)
}
fn try_get_raw_async(&self, format: &DataFormat) -> LocalBoxFuture<Result<Option<Rc<dyn Any>>, ClipboardError>> {
Box::pin(std::future::ready(PlatformDataTransferItem::try_get_raw_result(self, format)))
}
}