#![cfg_attr(not(feature = "reactor"), allow(dead_code, unused_imports))]
#[cfg(all(feature = "reactor", windows))]
pub(crate) mod iocp;
#[cfg(all(feature = "reactor", unix))]
pub(crate) mod ready;
use std::collections::VecDeque;
use std::io::IoSlice;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
use crate::buf::Buffer;
use crate::error::{NetError, OsErrorClass};
use crate::session::{Chunk, Output};
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub enum DriverKind {
Blocking,
Reactor,
Uring,
#[default]
Auto,
}
impl DriverKind {
pub(crate) fn resolve(self) -> DriverKind {
match self {
DriverKind::Auto if DriverKind::reactor_built() && !cfg!(net_io_force_blocking) => {
DriverKind::Reactor
}
DriverKind::Auto => DriverKind::Blocking,
other => other,
}
}
pub(crate) const fn reactor_built() -> bool {
cfg!(feature = "reactor")
}
}
#[cfg(unix)]
pub type BorrowedSocket<'a> = std::os::fd::BorrowedFd<'a>;
#[cfg(windows)]
pub type BorrowedSocket<'a> = std::os::windows::io::BorrowedSocket<'a>;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Token(pub u64);
impl Token {
pub(crate) fn index(self) -> usize {
(self.0 & 0xFFFF_FFFF) as usize
}
}
#[non_exhaustive]
#[derive(Debug)]
pub enum Operation {
Accept {
listener: Token,
},
Receive {
token: Token,
buffer: Buffer,
},
ReceiveZero {
token: Token,
},
Send {
token: Token,
chunks: SendChunks,
},
Connect {
token: Token,
addr: SocketAddr,
},
Close {
token: Token,
abortive: bool,
},
Nop {
token: Token,
},
}
impl Operation {
fn token(&self) -> Token {
match self {
Operation::Accept { listener } => *listener,
Operation::Receive { token, .. }
| Operation::ReceiveZero { token }
| Operation::Send { token, .. }
| Operation::Connect { token, .. }
| Operation::Close { token, .. }
| Operation::Nop { token } => *token,
}
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OperationKind {
Accept,
Receive,
Send,
Connect,
Close,
Nop,
}
#[non_exhaustive]
#[derive(Debug)]
pub struct Completion {
pub token: Token,
pub kind: OperationKind,
pub result: Result<usize, OsErrorClass>,
pub buffer: Option<Buffer>,
pub chunks: Option<SendChunks>,
}
impl Completion {
pub(crate) fn new(
token: Token,
kind: OperationKind,
result: Result<usize, OsErrorClass>,
) -> Completion {
Completion {
token,
kind,
result,
buffer: None,
chunks: None,
}
}
}
pub(crate) const COMPLETIONS: usize = 256;
#[derive(Debug)]
pub struct Completions {
items: Vec<Completion>,
}
impl Default for Completions {
fn default() -> Completions {
Completions::new()
}
}
impl Completions {
#[must_use]
pub fn new() -> Completions {
Completions {
items: Vec::with_capacity(COMPLETIONS),
}
}
#[must_use]
pub fn len(&self) -> usize {
self.items.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn drain(&mut self) -> impl Iterator<Item = Completion> + '_ {
self.items.drain(..)
}
#[cfg(feature = "reactor")]
pub(crate) fn push(&mut self, c: Completion) {
self.items.push(c);
}
#[cfg(feature = "reactor")]
pub(crate) fn has_room(&self) -> bool {
self.items.len() < COMPLETIONS
}
}
#[derive(Debug, Default)]
pub struct SendChunks {
pub(crate) chunks: VecDeque<Chunk>,
}
impl SendChunks {
#[must_use]
pub fn from_buffer(buffer: Buffer) -> SendChunks {
let mut chunks = VecDeque::with_capacity(1);
chunks.push_back(Chunk::Pooled(buffer, 0));
SendChunks { chunks }
}
pub(crate) fn take(output: &mut Output) -> SendChunks {
SendChunks {
chunks: std::mem::take(&mut output.chunks),
}
}
pub(crate) fn restore(self, output: &mut Output) {
output.chunks = self.chunks;
}
#[must_use]
pub fn pending(&self) -> usize {
self.chunks.iter().map(|c| c.remaining().len()).sum()
}
#[cfg(feature = "reactor")]
pub(crate) fn advance(&mut self, mut n: usize) -> bool {
while let Some(front) = self.chunks.front_mut() {
let rem = front.remaining().len();
if n < rem {
match front {
Chunk::Pooled(_, off) | Chunk::Static(_, off) => *off += n,
}
return true;
}
if self.chunks.len() == 1 {
return false;
}
n -= rem;
self.chunks.pop_front();
}
false
}
pub(crate) fn into_buffer(mut self) -> Option<Buffer> {
match self.chunks.pop_front() {
Some(Chunk::Pooled(b, _)) => Some(b),
_ => None,
}
}
#[cfg(feature = "reactor")]
pub(crate) fn slices<'a>(&'a self, out: &mut [IoSlice<'a>]) -> usize {
let mut n = 0;
for chunk in self.chunks.iter().take(out.len()) {
out[n] = IoSlice::new(chunk.remaining());
n += 1;
}
n
}
}
#[derive(Debug)]
pub struct Rejected {
pub operation: Operation,
}
#[derive(Clone, Debug)]
pub struct DriverWaker {
pub(crate) inner: Arc<WakerInner>,
}
#[cfg(feature = "reactor")]
pub(crate) type WakerInner = crate::sys::PollWaker;
#[cfg(not(feature = "reactor"))]
#[derive(Debug)]
pub(crate) struct WakerInner;
impl DriverWaker {
pub fn wake(&self) {
#[cfg(feature = "reactor")]
self.inner.wake();
}
}
#[cfg(feature = "reactor")]
pub fn new_reactor_driver(capacity: usize) -> Result<Box<dyn Driver>, NetError> {
#[cfg(unix)]
let driver = ready::ReadyDriver::new(capacity)?;
#[cfg(windows)]
let driver = iocp::IocpDriver::new(capacity)?;
Ok(Box::new(driver))
}
pub trait Driver: Send {
fn kind(&self) -> DriverKind;
fn register(&mut self, socket: BorrowedSocket<'_>, token: Token) -> Result<(), NetError>;
fn submit(&mut self, operation: Operation) -> Result<(), Rejected>;
fn wait(&mut self, out: &mut Completions, timeout: Option<Duration>)
-> Result<usize, NetError>;
fn cancel(&mut self, token: Token, which: OperationKind) -> Result<(), NetError>;
fn deregister(&mut self, token: Token) -> Result<(), NetError>;
fn waker(&self) -> DriverWaker;
}
pub(crate) fn operation_token(op: &Operation) -> Token {
op.token()
}