pub mod callback;
#[ cfg( not( target_arch = "wasm32" ) ) ]
mod copy;
mod mime;
#[ cfg( not( target_arch = "wasm32" ) ) ]
mod native;
#[ cfg( all( target_arch = "wasm32", not( feature = "web" ) ) ) ]
mod unsupported;
#[ cfg( not( target_arch = "wasm32" ) ) ]
use native as backend;
#[ cfg( all( target_arch = "wasm32", feature = "web" ) ) ]
use crate::platform::web::files as backend;
#[ cfg( all( target_arch = "wasm32", not( feature = "web" ) ) ) ]
use unsupported as backend;
use std::ffi::OsString;
use std::io;
use std::path::PathBuf;
use std::time::SystemTime;
use crate::ChannelSender;
pub use mime::mime_type;
pub const CHUNK: usize = 1 << 20;
#[ derive( Debug, Clone, Copy, PartialEq, Eq ) ]
pub enum Kind
{
File,
Directory,
}
#[ derive( Debug, Clone ) ]
pub struct Entry
{
pub name: OsString,
pub kind: Kind,
pub size: u64,
pub modified: Option<SystemTime>,
pub accessed: Option<SystemTime>,
}
#[ derive( Debug, Clone ) ]
pub struct Metadata
{
pub kind: Kind,
pub size: u64,
pub modified: Option<SystemTime>,
pub accessed: Option<SystemTime>,
}
#[ derive( Debug, Clone, PartialEq, Eq ) ]
pub struct Mount
{
pub path: PathBuf,
pub name: String,
}
pub( crate ) type Reply<T> = Box<dyn FnOnce( io::Result<T> ) + Send>;
pub( crate ) type Progress = Box<dyn Fn( u64, u64 ) + Send>;
fn reply<M: Send + 'static, T>( sender: &ChannelSender<M>, done: impl FnOnce( io::Result<T> ) -> M + Send + 'static ) -> Reply<T>
{
let sender = sender.clone();
Box::new( move |result| { let _ = sender.send( done( result ) ); } )
}
pub fn list<M: Send + 'static>( path: impl Into<PathBuf>, sender: &ChannelSender<M>, done: impl FnOnce( io::Result<Vec<Entry>> ) -> M + Send + 'static )
{
backend::list( path.into(), reply( sender, done ) );
}
pub fn stat<M: Send + 'static>( path: impl Into<PathBuf>, sender: &ChannelSender<M>, done: impl FnOnce( io::Result<Metadata> ) -> M + Send + 'static )
{
backend::stat( path.into(), reply( sender, done ) );
}
pub fn read<M: Send + 'static>( path: impl Into<PathBuf>, sender: &ChannelSender<M>, done: impl FnOnce( io::Result<Vec<u8>> ) -> M + Send + 'static )
{
backend::read( path.into(), None, reply( sender, done ) );
}
pub fn read_range<M: Send + 'static>( path: impl Into<PathBuf>, offset: u64, length: u64, sender: &ChannelSender<M>, done: impl FnOnce( io::Result<Vec<u8>> ) -> M + Send + 'static )
{
backend::read( path.into(), Some( ( offset, length ) ), reply( sender, done ) );
}
pub fn write<M: Send + 'static>( path: impl Into<PathBuf>, data: Vec<u8>, sender: &ChannelSender<M>, done: impl FnOnce( io::Result<()> ) -> M + Send + 'static )
{
backend::write( path.into(), data, reply( sender, done ) );
}
pub fn open_write<M: Send + 'static>( path: impl Into<PathBuf>, sender: &ChannelSender<M>, done: impl FnOnce( io::Result<Writer> ) -> M + Send + 'static )
{
let done = reply( sender, done );
backend::open_write( path.into(), Box::new( move |result| done( result.map( |handle| Writer { handle: Some( handle ) } ) ) ) );
}
pub fn create_dir<M: Send + 'static>( path: impl Into<PathBuf>, sender: &ChannelSender<M>, done: impl FnOnce( io::Result<()> ) -> M + Send + 'static )
{
backend::create_dir( path.into(), reply( sender, done ) );
}
pub fn rename<M: Send + 'static>( from: impl Into<PathBuf>, to: impl Into<PathBuf>, sender: &ChannelSender<M>, done: impl FnOnce( io::Result<()> ) -> M + Send + 'static )
{
backend::rename( from.into(), to.into(), reply( sender, done ) );
}
pub fn remove<M: Send + 'static>( path: impl Into<PathBuf>, sender: &ChannelSender<M>, done: impl FnOnce( io::Result<()> ) -> M + Send + 'static )
{
backend::remove( path.into(), false, reply( sender, done ) );
}
pub fn remove_all<M: Send + 'static>( path: impl Into<PathBuf>, sender: &ChannelSender<M>, done: impl FnOnce( io::Result<()> ) -> M + Send + 'static )
{
backend::remove( path.into(), true, reply( sender, done ) );
}
pub fn copy<M: Send + 'static>(
from: impl Into<PathBuf>,
to: impl Into<PathBuf>,
sender: &ChannelSender<M>,
progress: impl Fn( u64, u64 ) -> M + Send + 'static,
done: impl FnOnce( io::Result<()> ) -> M + Send + 'static,
) -> Operation
{
start_copy( from.into(), to.into(), false, sender, progress, done )
}
pub fn copy_all<M: Send + 'static>(
from: impl Into<PathBuf>,
to: impl Into<PathBuf>,
sender: &ChannelSender<M>,
progress: impl Fn( u64, u64 ) -> M + Send + 'static,
done: impl FnOnce( io::Result<()> ) -> M + Send + 'static,
) -> Operation
{
start_copy( from.into(), to.into(), true, sender, progress, done )
}
fn start_copy<M: Send + 'static>(
from: PathBuf,
to: PathBuf,
all: bool,
sender: &ChannelSender<M>,
progress: impl Fn( u64, u64 ) -> M + Send + 'static,
done: impl FnOnce( io::Result<()> ) -> M + Send + 'static,
) -> Operation
{
let progress_sender = sender.clone();
let progress: Progress = Box::new( move |copied, total| { let _ = progress_sender.send( progress( copied, total ) ); } );
Operation { handle: backend::copy( from, to, all, progress, reply( sender, done ) ) }
}
pub fn mount<M: Send + 'static>( sender: &ChannelSender<M>, done: impl FnOnce( io::Result<Mount> ) -> M + Send + 'static )
{
backend::mount( reply( sender, done ) );
}
pub fn unmount<M: Send + 'static>( path: impl Into<PathBuf>, sender: &ChannelSender<M>, done: impl FnOnce( io::Result<()> ) -> M + Send + 'static )
{
backend::unmount( path.into(), reply( sender, done ) );
}
static MOUNTS: std::sync::Mutex<Option<Vec<Mount>>> = std::sync::Mutex::new( None );
pub fn mounts() -> Option<Vec<Mount>>
{
MOUNTS.lock().ok()?.clone()
}
#[ cfg_attr( not( feature = "web" ), allow( dead_code ) ) ]
pub( crate ) fn set_mounts( mounts: &[ Mount ] )
{
if let Ok( mut held ) = MOUNTS.lock() { *held = Some( mounts.to_vec() ); }
}
pub struct Writer
{
handle: Option<backend::WriterHandle>,
}
impl Writer
{
pub fn write<M: Send + 'static>( &self, chunk: Vec<u8>, sender: &ChannelSender<M>, done: impl FnOnce( io::Result<()> ) -> M + Send + 'static )
{
let done = reply( sender, done );
match &self.handle
{
Some( handle ) => backend::write_chunk( handle, chunk, done ),
None => done( Err( io::ErrorKind::BrokenPipe.into() ) ),
}
}
pub fn close<M: Send + 'static>( mut self, sender: &ChannelSender<M>, done: impl FnOnce( io::Result<()> ) -> M + Send + 'static )
{
let done = reply( sender, done );
match self.handle.take()
{
Some( handle ) => backend::close( handle, done ),
None => done( Err( io::ErrorKind::BrokenPipe.into() ) ),
}
}
pub fn abort( mut self )
{
if let Some( handle ) = self.handle.take() { backend::abort( handle ); }
}
}
impl Drop for Writer
{
fn drop( &mut self )
{
if let Some( handle ) = self.handle.take() { backend::abort( handle ); }
}
}
pub struct Operation
{
handle: backend::OperationHandle,
}
impl Operation
{
pub fn cancel( &self )
{
backend::cancel( &self.handle );
}
}