use super::{ClipboardError, PlatformDataTransferItem};
use crate::input::{DataFormat, IAsyncDataTransfer, IAsyncDataTransferItem, IDataTransfer, IDataTransferItem};
use crate::reactive::IDisposable;
use std::cell::RefCell;
use std::rc::Rc;
pub trait PlatformDataTransferImpl {
fn provide_formats(&self) -> Result<Vec<DataFormat>, ClipboardError>;
fn provide_items(&self) -> Result<Vec<Rc<PlatformDataTransferItem>>, ClipboardError>;
fn dispose(&self, owner: &PlatformDataTransfer);
}
pub struct PlatformDataTransfer {
formats: RefCell<Option<Rc<[DataFormat]>>>,
items: RefCell<Option<Rc<[Rc<PlatformDataTransferItem>]>>>,
sync_items: RefCell<Option<Rc<[Rc<dyn IDataTransferItem>]>>>,
async_items: RefCell<Option<Rc<[Rc<dyn IAsyncDataTransferItem>]>>>,
platform_impl: Box<dyn PlatformDataTransferImpl>,
}
impl PlatformDataTransfer {
pub fn new(platform_impl: impl PlatformDataTransferImpl + 'static) -> Rc<PlatformDataTransfer> {
Rc::new(PlatformDataTransfer {
formats: RefCell::new(None),
items: RefCell::new(None),
sync_items: RefCell::new(None),
async_items: RefCell::new(None),
platform_impl: Box::new(platform_impl),
})
}
#[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)
}
pub fn are_formats_initialized(&self) -> bool {
self.formats.borrow().is_some()
}
#[track_caller]
pub fn items(&self) -> Rc<[Rc<PlatformDataTransferItem>]> {
match self.try_items() {
Ok(items) => items,
Err(error) => panic!("{error}"),
}
}
pub fn try_items(&self) -> Result<Rc<[Rc<PlatformDataTransferItem>]>, ClipboardError> {
if let Some(items) = self.items.borrow().as_ref() {
return Ok(items.clone());
}
let items: Rc<[Rc<PlatformDataTransferItem>]> = Rc::from(self.platform_impl.provide_items()?);
*self.items.borrow_mut() = Some(items.clone());
Ok(items)
}
pub fn are_items_initialized(&self) -> bool {
self.items.borrow().is_some()
}
}
impl IDisposable for PlatformDataTransfer {
fn dispose(&self) {
self.platform_impl.dispose(self)
}
}
impl IDataTransfer for PlatformDataTransfer {
fn formats(&self) -> Rc<[DataFormat]> {
PlatformDataTransfer::formats(self)
}
fn items(&self) -> Rc<[Rc<dyn IDataTransferItem>]> {
if let Some(items) = self.sync_items.borrow().as_ref() {
return items.clone();
}
let items: Rc<[Rc<dyn IDataTransferItem>]> =
PlatformDataTransfer::items(self).iter().map(|item| item.clone() as Rc<dyn IDataTransferItem>).collect();
*self.sync_items.borrow_mut() = Some(items.clone());
items
}
fn as_async_data_transfer(self: Rc<Self>) -> Option<Rc<dyn IAsyncDataTransfer>> {
Some(self)
}
}
impl IAsyncDataTransfer for PlatformDataTransfer {
fn formats(&self) -> Rc<[DataFormat]> {
PlatformDataTransfer::formats(self)
}
fn items(&self) -> Rc<[Rc<dyn IAsyncDataTransferItem>]> {
match IAsyncDataTransfer::try_items(self) {
Ok(items) => items,
Err(error) => panic!("{error}"),
}
}
fn try_formats(&self) -> Result<Rc<[DataFormat]>, ClipboardError> {
PlatformDataTransfer::try_formats(self)
}
fn try_items(&self) -> Result<Rc<[Rc<dyn IAsyncDataTransferItem>]>, ClipboardError> {
if let Some(items) = self.async_items.borrow().as_ref() {
return Ok(items.clone());
}
let items: Rc<[Rc<dyn IAsyncDataTransferItem>]> = PlatformDataTransfer::try_items(self)?
.iter()
.map(|item| item.clone() as Rc<dyn IAsyncDataTransferItem>)
.collect();
*self.async_items.borrow_mut() = Some(items.clone());
Ok(items)
}
fn as_data_transfer(self: Rc<Self>) -> Option<Rc<dyn IDataTransfer>> {
Some(self)
}
}