#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_cfg))]
extern crate alloc;
use alloc::string::String;
use core::future::Future;
use core::time::Duration;
use futures::Stream;
use mfio::backend::*;
use mfio::error::Result as MfioResult;
use mfio::io::NoPos;
use mfio::stdeq::{AsyncRead, AsyncWrite};
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use std::net::{SocketAddr, ToSocketAddrs};
#[cfg(feature = "std")]
pub use std::path::{Component, Path, PathBuf};
#[cfg(not(feature = "std"))]
pub use typed_path::{UnixComponent as Component, UnixPath as Path, UnixPathBuf as PathBuf};
#[cfg(feature = "native")]
#[cfg_attr(docsrs, doc(cfg(feature = "native")))]
pub mod native;
mod util;
#[cfg(any(feature = "virt", test, miri))]
#[cfg_attr(docsrs, doc(cfg(feature = "virt")))]
pub mod virt;
#[doc(hidden)]
pub mod __doctest;
#[cfg(any(feature = "test_suite", test))]
#[cfg_attr(docsrs, doc(cfg(feature = "test_suite")))]
pub mod test_suite;
#[cfg(feature = "native")]
pub use native::{NativeFile, NativeRt, NativeRtBuilder};
#[repr(C)]
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct OpenOptions {
pub read: bool,
pub write: bool,
pub create: bool,
pub create_new: bool,
pub truncate: bool,
}
impl OpenOptions {
pub const fn new() -> Self {
Self {
read: false,
write: false,
create: false,
create_new: false,
truncate: false,
}
}
pub fn read(self, read: bool) -> Self {
Self { read, ..self }
}
pub fn write(self, write: bool) -> Self {
Self { write, ..self }
}
pub fn create(self, create: bool) -> Self {
Self { create, ..self }
}
pub fn create_new(self, create_new: bool) -> Self {
Self { create_new, ..self }
}
pub fn truncate(self, truncate: bool) -> Self {
Self { truncate, ..self }
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum Shutdown {
Read,
Write,
Both,
}
#[cfg(feature = "std")]
use std::net;
#[cfg(feature = "std")]
impl From<net::Shutdown> for Shutdown {
fn from(o: net::Shutdown) -> Self {
match o {
net::Shutdown::Write => Self::Write,
net::Shutdown::Read => Self::Read,
net::Shutdown::Both => Self::Both,
}
}
}
#[cfg(feature = "std")]
impl From<Shutdown> for net::Shutdown {
fn from(o: Shutdown) -> Self {
match o {
Shutdown::Write => Self::Write,
Shutdown::Read => Self::Read,
Shutdown::Both => Self::Both,
}
}
}
pub trait Fs: IoBackend {
type DirHandle<'a>: DirHandle + 'a
where
Self: 'a;
fn current_dir(&self) -> &Self::DirHandle<'_>;
fn open<'a>(
&'a self,
path: &'a Path,
options: OpenOptions,
) -> <Self::DirHandle<'a> as DirHandle>::OpenFileFuture<'a> {
self.current_dir().open_file(path, options)
}
}
pub trait DirHandle: Sized {
type FileHandle: FileHandle;
type OpenFileFuture<'a>: Future<Output = MfioResult<Self::FileHandle>> + 'a
where
Self: 'a;
type PathFuture<'a>: Future<Output = MfioResult<PathBuf>> + 'a
where
Self: 'a;
type OpenDirFuture<'a>: Future<Output = MfioResult<Self>> + 'a
where
Self: 'a;
type ReadDir<'a>: Stream<Item = MfioResult<DirEntry>> + 'a
where
Self: 'a;
type ReadDirFuture<'a>: Future<Output = MfioResult<Self::ReadDir<'a>>> + 'a
where
Self: 'a;
type MetadataFuture<'a>: Future<Output = MfioResult<Metadata>> + 'a
where
Self: 'a;
type OpFuture<'a>: Future<Output = MfioResult<()>> + 'a
where
Self: 'a;
fn path(&self) -> Self::PathFuture<'_>;
fn read_dir(&self) -> Self::ReadDirFuture<'_>;
fn open_file<'a, P: AsRef<Path> + ?Sized>(
&'a self,
path: &'a P,
options: OpenOptions,
) -> Self::OpenFileFuture<'a>;
fn open_dir<'a, P: AsRef<Path> + ?Sized>(&'a self, path: &'a P) -> Self::OpenDirFuture<'a>;
fn metadata<'a, P: AsRef<Path> + ?Sized>(&'a self, path: &'a P) -> Self::MetadataFuture<'a>;
fn do_op<'a, P: AsRef<Path> + ?Sized>(&'a self, operation: DirOp<&'a P>) -> Self::OpFuture<'a>;
}
pub trait DirHandleExt: DirHandle {
fn set_permissions<'a, P: AsRef<Path> + ?Sized>(
&'a self,
path: &'a P,
permissions: Permissions,
) -> Self::OpFuture<'a> {
self.do_op(DirOp::SetPermissions { path, permissions })
}
fn remove_dir<'a, P: AsRef<Path> + ?Sized>(&'a self, path: &'a P) -> Self::OpFuture<'a> {
self.do_op(DirOp::RemoveDir { path })
}
fn remove_dir_all<'a, P: AsRef<Path> + ?Sized>(&'a self, path: &'a P) -> Self::OpFuture<'a> {
self.do_op(DirOp::RemoveDirAll { path })
}
fn create_dir<'a, P: AsRef<Path> + ?Sized>(&'a self, path: &'a P) -> Self::OpFuture<'a> {
self.do_op(DirOp::CreateDir { path })
}
fn create_dir_all<'a, P: AsRef<Path> + ?Sized>(&'a self, path: &'a P) -> Self::OpFuture<'a> {
self.do_op(DirOp::CreateDirAll { path })
}
fn remove_file<'a, P: AsRef<Path> + ?Sized>(&'a self, path: &'a P) -> Self::OpFuture<'a> {
self.do_op(DirOp::RemoveFile { path })
}
fn rename<'a, P: AsRef<Path> + ?Sized>(&'a self, from: &'a P, to: &'a P) -> Self::OpFuture<'a> {
self.do_op(DirOp::Rename { from, to })
}
fn copy<'a, P: AsRef<Path> + ?Sized>(&'a self, from: &'a P, to: &'a P) -> Self::OpFuture<'a> {
self.do_op(DirOp::Copy { from, to })
}
fn hard_link<'a, P: AsRef<Path> + ?Sized>(
&'a self,
from: &'a P,
to: &'a P,
) -> Self::OpFuture<'a> {
self.do_op(DirOp::HardLink { from, to })
}
}
impl<T: DirHandle> DirHandleExt for T {}
#[non_exhaustive]
#[derive(Serialize, Deserialize, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum DirOp<P: AsRef<Path>> {
SetPermissions { path: P, permissions: Permissions },
RemoveDir { path: P },
RemoveDirAll { path: P },
CreateDir { path: P },
CreateDirAll { path: P },
RemoveFile { path: P },
Rename { from: P, to: P },
Copy { from: P, to: P },
HardLink { from: P, to: P },
}
impl<P: AsRef<Path>> DirOp<P> {
pub fn as_path(&self) -> DirOp<&Path> {
match self {
Self::SetPermissions { path, permissions } => DirOp::SetPermissions {
path: path.as_ref(),
permissions: *permissions,
},
Self::RemoveDir { path } => DirOp::RemoveDir {
path: path.as_ref(),
},
Self::RemoveDirAll { path } => DirOp::RemoveDirAll {
path: path.as_ref(),
},
Self::CreateDir { path } => DirOp::CreateDir {
path: path.as_ref(),
},
Self::CreateDirAll { path } => DirOp::CreateDirAll {
path: path.as_ref(),
},
Self::RemoveFile { path } => DirOp::RemoveFile {
path: path.as_ref(),
},
Self::Rename { from, to } => DirOp::Rename {
from: from.as_ref(),
to: to.as_ref(),
},
Self::Copy { from, to } => DirOp::Copy {
from: from.as_ref(),
to: to.as_ref(),
},
Self::HardLink { from, to } => DirOp::HardLink {
from: from.as_ref(),
to: to.as_ref(),
},
}
}
}
impl<'a, P: AsRef<Path> + ?Sized> DirOp<&'a P> {
pub fn into_path(self) -> DirOp<&'a Path> {
match self {
Self::SetPermissions { path, permissions } => DirOp::SetPermissions {
path: path.as_ref(),
permissions,
},
Self::RemoveDir { path } => DirOp::RemoveDir {
path: path.as_ref(),
},
Self::RemoveDirAll { path } => DirOp::RemoveDirAll {
path: path.as_ref(),
},
Self::CreateDir { path } => DirOp::CreateDir {
path: path.as_ref(),
},
Self::CreateDirAll { path } => DirOp::CreateDirAll {
path: path.as_ref(),
},
Self::RemoveFile { path } => DirOp::RemoveFile {
path: path.as_ref(),
},
Self::Rename { from, to } => DirOp::Rename {
from: from.as_ref(),
to: to.as_ref(),
},
Self::Copy { from, to } => DirOp::Copy {
from: from.as_ref(),
to: to.as_ref(),
},
Self::HardLink { from, to } => DirOp::HardLink {
from: from.as_ref(),
to: to.as_ref(),
},
}
}
pub fn into_pathbuf(self) -> DirOp<PathBuf> {
match self {
Self::SetPermissions { path, permissions } => DirOp::SetPermissions {
path: path.as_ref().into(),
permissions,
},
Self::RemoveDir { path } => DirOp::RemoveDir {
path: path.as_ref().into(),
},
Self::RemoveDirAll { path } => DirOp::RemoveDirAll {
path: path.as_ref().into(),
},
Self::CreateDir { path } => DirOp::CreateDir {
path: path.as_ref().into(),
},
Self::CreateDirAll { path } => DirOp::CreateDirAll {
path: path.as_ref().into(),
},
Self::RemoveFile { path } => DirOp::RemoveFile {
path: path.as_ref().into(),
},
Self::Rename { from, to } => DirOp::Rename {
from: from.as_ref().into(),
to: to.as_ref().into(),
},
Self::Copy { from, to } => DirOp::Copy {
from: from.as_ref().into(),
to: to.as_ref().into(),
},
Self::HardLink { from, to } => DirOp::HardLink {
from: from.as_ref().into(),
to: to.as_ref().into(),
},
}
}
pub fn into_string(self) -> DirOp<String> {
match self {
Self::SetPermissions { path, permissions } => DirOp::SetPermissions {
path: path.as_ref().to_string_lossy().into(),
permissions,
},
Self::RemoveDir { path } => DirOp::RemoveDir {
path: path.as_ref().to_string_lossy().into(),
},
Self::RemoveDirAll { path } => DirOp::RemoveDirAll {
path: path.as_ref().to_string_lossy().into(),
},
Self::CreateDir { path } => DirOp::CreateDir {
path: path.as_ref().to_string_lossy().into(),
},
Self::CreateDirAll { path } => DirOp::CreateDirAll {
path: path.as_ref().to_string_lossy().into(),
},
Self::RemoveFile { path } => DirOp::RemoveFile {
path: path.as_ref().to_string_lossy().into(),
},
Self::Rename { from, to } => DirOp::Rename {
from: from.as_ref().to_string_lossy().into(),
to: to.as_ref().to_string_lossy().into(),
},
Self::Copy { from, to } => DirOp::Copy {
from: from.as_ref().to_string_lossy().into(),
to: to.as_ref().to_string_lossy().into(),
},
Self::HardLink { from, to } => DirOp::HardLink {
from: from.as_ref().to_string_lossy().into(),
to: to.as_ref().to_string_lossy().into(),
},
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
pub struct DirEntry {
pub name: String,
pub ty: FileType,
}
#[cfg(feature = "std")]
impl From<std::fs::DirEntry> for DirEntry {
fn from(d: std::fs::DirEntry) -> Self {
let ty = d
.file_type()
.map(|ty| {
if ty.is_file() {
FileType::File
} else if ty.is_dir() {
FileType::Directory
} else if ty.is_symlink() {
FileType::Symlink
} else {
FileType::Unknown
}
})
.unwrap_or(FileType::Unknown);
Self {
name: d.file_name().to_string_lossy().into(),
ty,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub enum FileType {
Unknown,
File,
Directory,
Symlink,
}
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug, Serialize, Deserialize)]
pub struct Permissions {}
#[cfg(feature = "std")]
impl From<std::fs::Permissions> for Permissions {
fn from(_: std::fs::Permissions) -> Self {
Self {}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct Metadata {
pub permissions: Permissions,
pub len: u64,
pub modified: Option<Duration>,
pub accessed: Option<Duration>,
pub created: Option<Duration>,
}
impl Metadata {
pub fn empty_file(permissions: Permissions, created: Option<Duration>) -> Self {
Self {
permissions,
len: 0,
modified: None,
accessed: None,
created,
}
}
pub fn empty_dir(permissions: Permissions, created: Option<Duration>) -> Self {
Self::empty_file(permissions, created)
}
}
pub trait FileHandle: AsyncRead<u64> + AsyncWrite<u64> {}
impl<T: AsyncRead<u64> + AsyncWrite<u64>> FileHandle for T {}
pub trait StreamHandle: AsyncRead<NoPos> + AsyncWrite<NoPos> {}
impl<T: AsyncRead<NoPos> + AsyncWrite<NoPos>> StreamHandle for T {}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub trait Tcp: IoBackend {
type StreamHandle: TcpStreamHandle;
type ListenerHandle: TcpListenerHandle<StreamHandle = Self::StreamHandle>;
type ConnectFuture<'a, A: ToSocketAddrs + Send + 'a>: Future<Output = MfioResult<Self::StreamHandle>>
+ 'a
where
Self: 'a;
type BindFuture<'a, A: ToSocketAddrs + Send + 'a>: Future<Output = MfioResult<Self::ListenerHandle>>
+ 'a
where
Self: 'a;
fn connect<'a, A: ToSocketAddrs + Send + 'a>(&'a self, addrs: A) -> Self::ConnectFuture<'a, A>;
fn bind<'a, A: ToSocketAddrs + Send + 'a>(&'a self, addrs: A) -> Self::BindFuture<'a, A>;
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub trait TcpStreamHandle: StreamHandle {
fn local_addr(&self) -> MfioResult<SocketAddr>;
fn peer_addr(&self) -> MfioResult<SocketAddr>;
fn shutdown(&self, how: Shutdown) -> MfioResult<()>;
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub trait TcpListenerHandle: Stream<Item = (Self::StreamHandle, SocketAddr)> {
type StreamHandle: TcpStreamHandle;
fn local_addr(&self) -> MfioResult<SocketAddr>;
}