use std::{
io,
mem::ManuallyDrop,
path::{Path, PathBuf},
};
pub mod buf;
pub use buf::*;
#[cfg(feature = "virtual")]
pub mod virtual_io;
#[cfg(feature = "virtual")]
pub use virtual_io::{VirtualIo, VirtualIoConfig};
#[cfg(feature = "wasm")]
pub mod wasm_io;
#[cfg(feature = "wasm")]
pub use wasm_io::{WasmIo, WasmIoConfig};
#[cfg(feature = "linux")]
pub mod linux_io;
#[cfg(feature = "linux")]
pub use linux_io::{LinuxIo, LinuxIoConfig};
#[cfg(test)]
mod tests;
#[derive(Default, Clone)]
pub struct OpenOptions {
pub read: bool,
pub write: bool,
pub create: bool,
pub create_new: bool,
pub truncate: bool,
pub direct: bool,
pub dsync: bool,
}
impl OpenOptions {
pub fn new() -> Self {
Default::default()
}
pub fn read(mut self, read: bool) -> Self {
self.read = read;
self
}
pub fn write(mut self, write: bool) -> Self {
self.write = write;
self
}
pub fn create(mut self, create: bool) -> Self {
self.create = create;
self
}
pub fn create_new(mut self, create_new: bool) -> Self {
self.create_new = create_new;
self
}
pub fn truncate(mut self, truncate: bool) -> Self {
self.truncate = truncate;
self
}
pub fn direct(mut self, direct: bool) -> Self {
self.direct = direct;
self
}
pub fn dsync(mut self, dsync: bool) -> Self {
self.dsync = dsync;
self
}
#[cfg(feature = "linux")]
pub const fn to_libc_flags(&self) -> i32 {
let mut flags = match (self.read, self.write) {
(true, true) => libc::O_RDWR,
(false, true) => libc::O_WRONLY,
_ => libc::O_RDONLY,
};
if self.create {
flags |= libc::O_CREAT;
}
if self.truncate {
flags |= libc::O_TRUNC;
}
if self.create_new {
flags |= libc::O_CREAT | libc::O_EXCL;
}
if self.direct {
flags |= libc::O_DIRECT;
}
if self.dsync {
flags |= libc::O_DSYNC;
}
flags
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct OpHandle(pub u64);
pub struct ReadHandle<B: IoBufMut> {
buf: B,
}
impl<B: IoBufMut> ReadHandle<B> {
#[cfg(any(feature = "virtual", feature = "linux", feature = "wasm"))]
pub(crate) fn new(buf: B) -> Self {
Self { buf }
}
pub unsafe fn complete(self, bytes_read: u32) -> B {
let mut this = ManuallyDrop::new(self);
unsafe { this.buf.set_init(bytes_read as usize) };
unsafe { std::ptr::read(&this.buf) }
}
}
impl<B: IoBufMut> Drop for ReadHandle<B> {
fn drop(&mut self) {
panic!("ReadHandle dropped before completion");
}
}
pub struct WriteHandle<B: IoBuf> {
buf: B,
}
impl<B: IoBuf> WriteHandle<B> {
#[cfg(any(feature = "virtual", feature = "linux", feature = "wasm"))]
pub(crate) fn new(buf: B) -> Self {
Self { buf }
}
pub fn complete(self) -> B {
let this = ManuallyDrop::new(self);
unsafe { std::ptr::read(&this.buf) }
}
}
impl<B: IoBuf> Drop for WriteHandle<B> {
fn drop(&mut self) {
panic!("WriteHandle dropped before completion");
}
}
pub struct DirEntry {
pub path: PathBuf,
pub is_dir: bool,
}
pub trait Statx: Sized {
fn stx_size(&self) -> u64;
}
pub struct FstatHandle<S: Statx> {
statx: Box<S>,
}
impl<S: Statx> FstatHandle<S> {
#[cfg(any(feature = "virtual", feature = "linux", feature = "wasm"))]
pub(crate) fn new(statx: Box<S>) -> Self {
Self { statx }
}
pub fn complete(self) -> S {
let this = ManuallyDrop::new(self);
let statx = unsafe { std::ptr::read(&this.statx as *const Box<S>) };
*statx
}
}
impl<S: Statx> Drop for FstatHandle<S> {
fn drop(&mut self) {
panic!("StatHandle dropped before completion");
}
}
pub trait Io: 'static {
fn block_size(&self) -> usize;
fn now(&self) -> std::time::Duration;
type Fd: Copy;
unsafe fn into_fd(result: u32) -> Self::Fd;
type RegisteredBuf: IoBufMut;
fn acquire_buf(&mut self) -> Option<Self::RegisteredBuf>;
fn release_buf(&mut self, buf: Self::RegisteredBuf);
type Statx: Statx;
fn fstat(&mut self, fd: Self::Fd, handle: OpHandle) -> io::Result<FstatHandle<Self::Statx>>;
fn open(&mut self, path: &Path, opts: OpenOptions, handle: OpHandle) -> io::Result<()>;
fn close(&mut self, fd: Self::Fd, handle: OpHandle) -> io::Result<()>;
fn read_at<B: IoBufMut>(
&mut self,
fd: Self::Fd,
buf: B,
offset: u64,
handle: OpHandle,
) -> Result<ReadHandle<B>, (io::Error, B)>;
fn write_at<B: IoBuf>(
&mut self,
fd: Self::Fd,
buf: B,
offset: u64,
handle: OpHandle,
) -> Result<WriteHandle<B>, (io::Error, B)>;
fn fsync(&mut self, fd: Self::Fd, handle: OpHandle) -> io::Result<()>;
fn rename(&mut self, from: &Path, to: &Path, handle: OpHandle) -> io::Result<()>;
fn remove(&mut self, path: &Path, handle: OpHandle) -> io::Result<()>;
fn poll(&mut self) -> io::Result<()>;
fn in_flight(&self) -> usize;
fn park(&mut self) -> io::Result<()>;
fn completions(&mut self) -> &mut Completions;
fn get_cqe(&mut self, handle: OpHandle) -> Option<io::Result<u32>> {
let completions = self.completions();
let idx = completions.iter().position(|(h, _)| *h == handle)?;
let (_, result) = completions.swap_remove(idx);
Some(result)
}
fn list_dir(&self, path: &Path) -> io::Result<Vec<DirEntry>>;
fn create_dir_all(&self, path: &Path) -> io::Result<()>;
}
pub type Completions = Vec<(OpHandle, io::Result<u32>)>;