use std::any::Any;
use std::fs::File;
use std::net::{SocketAddr, TcpListener, TcpStream};
use std::os::fd::{AsRawFd, RawFd};
use std::path::PathBuf;
use std::time::Duration;
use crate::buffer::{Buffer, Completed, Submitted};
use crate::error::{Error, Result};
#[doc(hidden)]
#[derive(Debug)]
#[non_exhaustive]
pub enum CompletionPayload {
Unit,
Bytes(usize),
Read {
buffer: Buffer<Completed>,
bytes: usize,
},
Recv {
stream: std::net::TcpStream,
buffer: Buffer<Completed>,
bytes: usize,
},
ReadVectored {
buffers: Vec<Buffer<Completed>>,
bytes: usize,
},
GpuRead {
buffer: crate::ops::AlignedBuffer,
bytes: usize,
},
LinkedChain(Vec<CompletionPayload>),
File(File),
Stream(TcpStream),
Metadata {
size: u64,
is_file: bool,
is_dir: bool,
},
}
#[doc(hidden)]
#[derive(Debug)]
#[non_exhaustive]
pub enum OpDescriptor {
Read {
file: File,
offset: u64,
buffer: Buffer<Submitted>,
len: Option<usize>,
},
Write {
file: File,
offset: u64,
buffer: Buffer<Submitted>,
},
ReadVectored {
file: File,
offset: u64,
buffers: Vec<Buffer<Submitted>>,
},
ReadGpu {
file: File,
offset: u64,
buffer: crate::ops::AlignedBuffer,
},
WriteVectored {
file: File,
offset: u64,
buffers: Vec<Buffer<Submitted>>,
},
Connect {
addr: SocketAddr,
timeout: Option<Duration>,
},
Accept {
listener: TcpListener,
},
Send {
stream: TcpStream,
buffer: Buffer<Submitted>,
},
Recv {
stream: TcpStream,
buffer: Buffer<Submitted>,
},
OpenAt {
dir: Option<File>,
path: PathBuf,
flags: u32,
read: bool,
write: bool,
create: bool,
truncate: bool,
},
OpenAtDirect {
dir: Option<File>,
path: PathBuf,
flags: u32,
read: bool,
write: bool,
create: bool,
truncate: bool,
slot: u32,
},
ReadFixed {
slot: u32,
offset: u64,
buffer: Buffer<Submitted>,
},
CloseFixed {
slot: u32,
},
Statx {
path: PathBuf,
},
Fsync {
file: File,
},
Cancel {
target: u64,
},
Linked {
descriptors: Vec<OpDescriptor>,
},
Splice {
fd_in: File,
off_in: Option<u64>,
fd_out: File,
off_out: Option<u64>,
len: usize,
},
Madvise {
file: File,
advice: MadviseAdvice,
},
Nop,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum MadviseAdvice {
Sequential,
Random,
DontNeed,
Normal,
}
pub trait Op: Send + 'static {
type Output: Send + 'static;
fn name(&self) -> &'static str;
fn into_descriptor(self) -> Result<OpDescriptor>;
fn map_completion(payload: CompletionPayload) -> Result<Self::Output>;
}
pub(crate) type BoxedMapper =
Box<dyn FnOnce(CompletionPayload) -> Result<Box<dyn Any + Send>> + Send>;
pub(crate) fn boxed_mapper<O: Op>() -> BoxedMapper {
Box::new(|payload| {
let mapped = O::map_completion(payload)?;
Ok(Box::new(mapped))
})
}
#[doc(hidden)]
pub fn validate_fd<T: AsRawFd>(value: &T, context: &str) -> Result<RawFd> {
let fd = value.as_raw_fd();
if fd < 0 {
return Err(Error::validation(
format!("{context} has an invalid file descriptor"),
"ensure the file or socket is open before building the operation",
));
}
Ok(fd)
}