#![allow(clippy::disallowed_types, reason = "traits require the `Arc` from std")]
mod executor_error;
mod no_std_runtime;
#[cfg(feature = "std")]
mod std_executor;
#[cfg(feature = "std")]
mod std_runtime;
#[cfg(feature = "tokio")]
mod tokio_executor;
use crate::stream::{TcpListener, TcpStream};
use core::net::SocketAddr;
pub use executor_error::ExecutorError;
pub use no_std_runtime::NoStdRuntime;
#[cfg(feature = "tokio")]
pub use tokio_executor::{TokioExecutor, TokioSpawnFutureFuture};
#[cfg(feature = "std")]
pub use {
std_executor::{StdExecutor, StdSpawnFuture, StdSpawnLocalFuture},
std_runtime::{SpawnFuture, StdRuntime},
};
#[derive(Clone, Copy, Debug)]
pub enum ExecutorTy {
Std,
Tokio,
}
pub trait Executor: Default {
const TY: ExecutorTy;
type LocalRuntime: Runtime;
type SpawnFuture<T>: Future<Output = crate::Result<T>>;
type SpawnLocalFuture<T>: Future<Output = crate::Result<T>>;
type TcpListener: TcpListener<TcpStream = Self::TcpStream>;
type TcpStream: TcpStream<Executor = Self>;
fn lookup_host(
host: (&str, u16),
) -> impl Future<Output = crate::Result<impl Iterator<Item = SocketAddr>>>;
fn spawn<F>(&self, future: F) -> Self::SpawnFuture<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static;
fn spawn_local<F>(&self, future: F) -> Self::SpawnLocalFuture<F::Output>
where
F: Future + 'static,
F::Output: 'static;
}
pub trait Runtime: Sized {
fn new() -> crate::Result<Self>;
fn block_on<F>(&self, future: F) -> F::Output
where
F: Future;
}
#[cfg(feature = "std")]
async fn tcp_listener_std<EX>(
addr: (&str, u16),
_tcp_params: crate::misc::TcpParams,
) -> crate::Result<std::net::TcpListener>
where
EX: Executor,
{
let socket_addr = crate::misc::into_rslt(EX::lookup_host(addr).await?.next())?;
cfg_select! {
feature = "socket2" => {
let domain = if socket_addr.is_ipv4() {
socket2::Domain::IPV4
} else {
socket2::Domain::IPV6
};
let socket = socket2::Socket::new(domain, socket2::Type::STREAM, None)?;
if let Some(elem) = _tcp_params.reuse_address {
socket.set_reuse_address(elem)?;
}
#[cfg(not(any(
target_os = "cygwin",
target_os = "illumos",
target_os = "solaris",
target_os = "wasi"
)))]
if let Some(elem) = _tcp_params.reuse_port {
socket.set_reuse_port(elem)?;
}
socket.set_tcp_nodelay(_tcp_params.tcp_nodelay)?;
socket.bind(&socket_addr.into())?;
socket.listen(_tcp_params.listen)?;
Ok(std::net::TcpListener::from(socket))
},
_ => Ok(std::net::TcpListener::bind(socket_addr)?)
}
}