use crate::Instant;
use std::net::{IpAddr, SocketAddr};
use std::time::Duration;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub struct Token(pub u64);
macro_rules! id {
($name:ident) => {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct $name {
pub(crate) owner: u64,
pub(crate) key: u64,
}
impl $name {
pub fn index(self) -> usize {
self.key as u32 as usize
}
pub fn key(self) -> u64 {
self.key
}
pub fn owner(self) -> u64 {
self.owner
}
}
};
}
id!(Handle);
id!(OpId);
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum RawTransport {
Fd(i32),
Socket(usize),
Handle(usize),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ErrorKind {
Cancelled,
Unsupported,
InvalidInput,
NotFound,
WouldBlock,
TimedOut,
ConnectionRefused,
ConnectionReset,
BrokenPipe,
ResourceLimit,
PermissionDenied,
AlreadyExists,
NotADirectory,
IsADirectory,
DirectoryNotEmpty,
Other,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Error {
pub kind: ErrorKind,
pub os: Option<i32>,
}
impl Error {
pub const fn new(kind: ErrorKind) -> Self {
Self { kind, os: None }
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
use std::io::ErrorKind as I;
let kind = match e.kind() {
I::Unsupported => ErrorKind::Unsupported,
I::InvalidInput => ErrorKind::InvalidInput,
I::NotFound => ErrorKind::NotFound,
I::WouldBlock => ErrorKind::WouldBlock,
I::TimedOut => ErrorKind::TimedOut,
I::ConnectionRefused => ErrorKind::ConnectionRefused,
I::ConnectionReset | I::ConnectionAborted => ErrorKind::ConnectionReset,
I::BrokenPipe => ErrorKind::BrokenPipe,
I::OutOfMemory => ErrorKind::ResourceLimit,
I::PermissionDenied => ErrorKind::PermissionDenied,
I::AlreadyExists => ErrorKind::AlreadyExists,
I::NotADirectory => ErrorKind::NotADirectory,
I::IsADirectory => ErrorKind::IsADirectory,
I::DirectoryNotEmpty => ErrorKind::DirectoryNotEmpty,
_ => ErrorKind::Other,
};
Self {
kind,
os: e.raw_os_error(),
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?} (OS {:?})", self.kind, self.os)
}
}
impl std::error::Error for Error {}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Clone, Copy, Debug)]
pub enum Timeout {
Now,
After(Duration),
Until(Instant),
Forever,
}
impl Timeout {
pub fn deadline(self, now: Instant) -> Option<Instant> {
match self {
Self::Now => Some(now),
Self::After(d) => now.checked_add(d),
Self::Until(t) => Some(t),
Self::Forever => None,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct Config {
pub max_handles: usize,
pub max_operations: usize,
pub events_per_turn: usize,
pub pooled_buffers: usize,
pub pooled_buffer_size: usize,
pub post_capacity: usize,
pub blocking_pool: crate::PoolConfig,
}
impl Default for Config {
fn default() -> Self {
Self {
max_handles: 1024,
max_operations: 4096,
events_per_turn: 256,
pooled_buffers: 256,
pooled_buffer_size: 16 * 1024,
post_capacity: 1024,
blocking_pool: crate::PoolConfig::default(),
}
}
}
impl Config {
pub fn single_connection() -> Self {
Self {
max_handles: 8,
max_operations: 16,
events_per_turn: 16,
pooled_buffers: 2,
pooled_buffer_size: 16 * 1024,
post_capacity: 16,
blocking_pool: crate::PoolConfig::default(),
}
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct TcpOpts {
pub nodelay: bool,
pub connect_timeout: Option<Duration>,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum ReusePort {
#[default]
No,
Share,
Distribute,
}
impl ReusePort {
pub const fn is_enabled(self) -> bool {
!matches!(self, Self::No)
}
}
#[derive(Clone, Copy, Debug)]
pub struct ListenOpts {
pub reuse_port: ReusePort,
pub backlog: u32,
pub accept_defaults: AcceptDefaults,
}
impl Default for ListenOpts {
fn default() -> Self {
Self {
reuse_port: ReusePort::No,
backlog: 128,
accept_defaults: AcceptDefaults::EMPTY,
}
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct AcceptDefaults {
pub nodelay: bool,
pub keep_alive: Option<KeepAlive>,
}
impl AcceptDefaults {
pub const EMPTY: Self = Self {
nodelay: false,
keep_alive: None,
};
pub const fn is_empty(self) -> bool {
!self.nodelay && self.keep_alive.is_none()
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct KeepAlive {
pub idle: Option<Duration>,
pub interval: Option<Duration>,
pub count: Option<u32>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct MulticastGroup {
pub group: IpAddr,
pub interface: u32,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SocketOption {
NoDelay(bool),
KeepAlive(Option<KeepAlive>),
Linger(Option<Duration>),
RecvBufferSize(u32),
SendBufferSize(u32),
Ttl(u32),
Ipv6Only(bool),
Broadcast(bool),
MulticastTtl(u32),
MulticastLoop(bool),
MulticastJoin(MulticastGroup),
MulticastLeave(MulticastGroup),
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SocketOptionKind {
NoDelay,
KeepAlive,
Linger,
RecvBufferSize,
SendBufferSize,
Ttl,
Ipv6Only,
Broadcast,
MulticastTtl,
MulticastLoop,
}
#[derive(Clone, Copy, Debug, Default)]
pub struct UdpOpts {
pub reuse_port: ReusePort,
}
#[derive(Clone, Copy, Debug)]
pub enum Integration {
Fd(i32),
Event(usize),
HostCallback,
RuntimeOwned,
}
#[derive(Debug)]
pub enum Open {
#[cfg(turnloop_backend = "web")]
Fetch {
url: String,
},
#[cfg(turnloop_backend = "web")]
WebSocket {
url: String,
},
Pipe(crate::PipeName),
PipeListener {
name: crate::PipeName,
opts: ListenOpts,
},
Stdio(crate::Stdio),
Tcp {
addr: SocketAddr,
opts: TcpOpts,
},
Listener {
addr: SocketAddr,
opts: ListenOpts,
},
Udp {
addr: SocketAddr,
opts: UdpOpts,
},
}