use crate::{backend::Backend, *};
use futures_io::{AsyncRead, AsyncWrite};
use std::{
cell::{Cell, RefCell, RefMut},
future::Future,
io,
net::SocketAddr,
pin::Pin,
rc::Rc,
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
task::{Context, Poll, Wake, Waker},
time::Duration,
};
const TAG: u64 = 1 << 63;
const INTERNAL: Token = Token(TAG);
#[derive(Clone, Copy, Debug)]
pub struct ExecutorConfig {
pub tasks: usize,
pub operations: usize,
pub buffer_size: usize,
}
impl Default for ExecutorConfig {
fn default() -> Self {
Self {
tasks: 1024,
operations: 1024,
buffer_size: 16 * 1024,
}
}
}
impl ExecutorConfig {
pub fn single_connection() -> Self {
Self {
tasks: 4,
operations: 8,
buffer_size: 16 * 1024,
}
}
}
struct IoSlot {
generation: u32,
used: bool,
abandoned: bool,
op: Option<OpId>,
timer: Option<Handle>,
closing: Option<Handle>,
result: Option<OpResult>,
waker: Option<Waker>,
bytes: Box<[u8]>,
offset: usize,
}
#[derive(Clone, Copy)]
struct Key {
index: usize,
generation: u32,
}
impl Key {
fn token(self) -> Token {
Token(TAG | ((self.generation as u64) << 32) | self.index as u64)
}
}
struct TaskWake {
ready: AtomicBool,
cancelled: AtomicBool,
notifier: Notifier,
}
impl Wake for TaskWake {
fn wake(self: Arc<Self>) {
self.wake_by_ref();
}
fn wake_by_ref(self: &Arc<Self>) {
self.ready.store(true, Ordering::Release);
let _ = self.notifier.notify();
}
}
struct Task {
future: Pin<Box<dyn Future<Output = ()>>>,
wake: Arc<TaskWake>,
}
struct Shared<B: Backend> {
driver: RefCell<Driver<B>>,
slots: RefCell<Vec<IoSlot>>,
tasks: RefCell<Vec<Option<Task>>>,
occupied: RefCell<Vec<bool>>,
closed: Cell<bool>,
}
impl<B: Backend> Shared<B> {
fn reserve(&self, cx: &Context<'_>) -> Result<Key> {
let mut slots = self.slots.borrow_mut();
for (index, slot) in slots.iter_mut().enumerate() {
if !slot.used && slot.generation < 0x7fff_ffff {
slot.generation += 1;
slot.used = true;
slot.abandoned = false;
slot.waker = Some(cx.waker().clone());
slot.offset = 0;
return Ok(Key {
index,
generation: slot.generation,
});
}
}
Err(Error::new(ErrorKind::ResourceLimit))
}
fn free(&self, key: Key) {
let mut slots = self.slots.borrow_mut();
let slot = &mut slots[key.index];
debug_assert_eq!(slot.generation, key.generation);
let result = slot.result.take();
slot.used = false;
slot.op = None;
slot.waker = None;
slot.timer = None;
slot.closing = None;
drop(slots);
if let Some(
OpResult::Accepted { conn, .. }
| OpResult::PipeAccepted { conn }
| OpResult::HandleReceived { handle: conn },
) = result
{
let _ = self.driver.borrow_mut().close(conn, INTERNAL);
}
}
fn abandon(&self, key: Key) {
let (op, timer, done) = {
let mut slots = self.slots.borrow_mut();
let slot = &mut slots[key.index];
if !slot.used || slot.generation != key.generation {
return;
}
slot.abandoned = true;
slot.waker = None;
(slot.op, slot.timer.take(), slot.result.is_some())
};
if let Some(timer) = timer {
let _ = self.driver.borrow_mut().close(timer, INTERNAL);
} else if let Some(op) = op {
self.driver.borrow_mut().cancel(op);
}
if done || op.is_none() {
self.free(key);
}
}
fn result(&self, key: Key, cx: &Context<'_>) -> Option<OpResult> {
let mut slots = self.slots.borrow_mut();
let slot = &mut slots[key.index];
if slot.waker.as_ref().is_none_or(|w| !w.will_wake(cx.waker())) {
slot.waker = Some(cx.waker().clone());
}
slot.result.take()
}
fn claims(&self, completion: &Completion) -> bool {
if matches!(completion.result, OpResult::Closed) {
for slot in self.slots.borrow_mut().iter_mut() {
if slot.used && slot.closing.is_some() && slot.closing == completion.handle {
slot.result = Some(OpResult::Closed);
if let Some(w) = &slot.waker {
w.wake_by_ref();
}
}
}
}
completion.token.0 & TAG != 0
}
fn dispatch(&self, completion: Completion) {
debug_assert!(completion.token.0 & TAG != 0, "unclaimed completion");
let key = Key {
index: completion.token.0 as u32 as usize,
generation: ((completion.token.0 & !TAG) >> 32) as u32,
};
let (waker, abandoned, timer) = {
let mut slots = self.slots.borrow_mut();
let Some(slot) = slots.get_mut(key.index) else {
return;
};
if !slot.used || slot.generation != key.generation {
return;
}
let timer = slot.timer.take();
slot.result = Some(completion.result);
(slot.waker.take(), slot.abandoned, timer)
};
if let Some(timer) = timer {
let _ = self.driver.borrow_mut().close(timer, INTERNAL);
}
if abandoned {
self.free(key);
} else if let Some(waker) = waker {
waker.wake();
}
}
}
pub struct LocalExecutor<B: Backend> {
shared: Rc<Shared<B>>,
out: Completions,
}
impl<B: Backend> LocalExecutor<B> {
pub fn new(config: Config) -> Result<Self> {
Self::with_config(config, ExecutorConfig::default())
}
pub fn with_config(config: Config, executor: ExecutorConfig) -> Result<Self> {
if executor.tasks == 0
|| executor.operations == 0
|| executor.operations > u32::MAX as usize
|| executor.buffer_size == 0
{
return Err(Error::new(ErrorKind::InvalidInput));
}
let driver = Driver::<B>::new(config)?;
Ok(Self {
shared: Rc::new(Shared {
driver: RefCell::new(driver),
slots: RefCell::new(
(0..executor.operations)
.map(|_| IoSlot {
generation: 0,
used: false,
abandoned: false,
op: None,
timer: None,
closing: None,
result: None,
waker: None,
bytes: vec![0; executor.buffer_size].into_boxed_slice(),
offset: 0,
})
.collect(),
),
tasks: RefCell::new((0..executor.tasks).map(|_| None).collect()),
occupied: RefCell::new(vec![false; executor.tasks]),
closed: Cell::new(false),
}),
out: Completions::with_capacity(config.events_per_turn),
})
}
pub fn handle(&self) -> ExecutorHandle<B> {
ExecutorHandle {
shared: self.shared.clone(),
}
}
pub fn driver(&self) -> RefMut<'_, Driver<B>> {
self.shared.driver.borrow_mut()
}
pub fn unclaimed(&mut self) -> &mut Completions {
&mut self.out
}
pub fn spawn_local<F: Future + 'static>(&self, future: F) -> Result<JoinHandle<F::Output>> {
self.handle().spawn_local(future)
}
pub fn run_ready(&mut self) -> usize {
let count = self.shared.tasks.borrow().len();
let mut polls = 0;
for i in 0..count {
let task = {
let mut tasks = self.shared.tasks.borrow_mut();
if tasks[i]
.as_ref()
.is_none_or(|t| !t.wake.ready.swap(false, Ordering::AcqRel))
{
continue;
}
tasks[i].take().expect("ready task")
};
let mut task = task;
let done = if task.wake.cancelled.load(Ordering::Acquire) {
true
} else {
let waker = Waker::from(task.wake.clone());
polls += 1;
task.future
.as_mut()
.poll(&mut Context::from_waker(&waker))
.is_ready()
};
if done {
self.shared.occupied.borrow_mut()[i] = false;
drop(task);
} else {
self.shared.tasks.borrow_mut()[i] = Some(task);
}
}
polls
}
pub fn turn(&mut self, timeout: crate::Timeout) -> Result<TurnInfo> {
let mut out = std::mem::replace(
&mut self.out,
Completions {
entries: Vec::new(),
},
);
let result = self.turn_into(timeout, &mut out);
self.out = out;
result
}
pub fn turn_into(
&mut self,
timeout: crate::Timeout,
out: &mut Completions,
) -> Result<TurnInfo> {
self.run_ready();
let ready = self
.shared
.tasks
.borrow()
.iter()
.flatten()
.any(|t| t.wake.ready.load(Ordering::Acquire));
let idle = !self.alive();
let info = self.shared.driver.borrow_mut().turn(
if ready || idle {
crate::Timeout::Now
} else {
timeout
},
out,
)?;
let shared = &self.shared;
for completion in out.entries.extract_if(.., |c| shared.claims(c)) {
shared.dispatch(completion);
}
self.run_ready();
Ok(info)
}
pub fn alive(&self) -> bool {
self.shared.occupied.borrow().iter().any(|&v| v) || self.shared.driver.borrow().alive()
}
}
impl<B: Backend> Drop for LocalExecutor<B> {
fn drop(&mut self) {
self.shared.closed.set(true);
let count = self.shared.tasks.borrow().len();
for i in 0..count {
let task = self.shared.tasks.borrow_mut()[i].take();
drop(task);
}
}
}
pub struct ExecutorHandle<B: Backend> {
shared: Rc<Shared<B>>,
}
impl<B: Backend> Clone for ExecutorHandle<B> {
fn clone(&self) -> Self {
Self {
shared: self.shared.clone(),
}
}
}
impl<B: Backend> ExecutorHandle<B> {
pub fn driver(&self) -> RefMut<'_, Driver<B>> {
self.shared.driver.borrow_mut()
}
pub fn now(&self) -> Instant {
self.shared.driver.borrow().now()
}
pub fn resolve(&self, request: DnsRequest) -> Resolve<B> {
Resolve {
executor: self.clone(),
request: Some(request),
key: None,
}
}
pub fn blocking<F: FnOnce() -> BlockingResult + Send + 'static>(&self, work: F) -> Blocking<B> {
Blocking {
executor: self.clone(),
work: Some(Box::new(work)),
key: None,
}
}
pub fn close(&self, handle: Handle) -> Close<B> {
Close {
executor: self.clone(),
handle: Some(handle),
key: None,
}
}
pub fn connect(&self, addr: SocketAddr, opts: TcpOpts) -> Connect<B> {
Connect {
executor: self.clone(),
address: addr,
opts,
key: None,
handle: None,
}
}
pub fn timeout_at<F: Future>(&self, deadline: Instant, future: F) -> Timeout<B, F> {
Timeout {
future,
sleep: self.sleep_until(deadline),
}
}
pub fn io(&self, handle: Handle) -> AsyncIo<B> {
AsyncIo {
shared: self.shared.clone(),
handle,
peer: None,
read: None,
write: None,
shutdown: None,
write_shut: false,
closed: false,
}
}
pub fn udp(&self, handle: Handle, peer: SocketAddr) -> AsyncIo<B> {
let mut io = self.io(handle);
io.peer = Some(peer);
io
}
pub fn sleep_until(&self, deadline: Instant) -> Sleep<B> {
Sleep {
shared: self.shared.clone(),
deadline,
key: None,
done: false,
}
}
pub fn sleep(&self, duration: Duration) -> Sleep<B> {
self.sleep_until(self.shared.driver.borrow().now() + duration)
}
pub fn timeout<F: Future>(&self, duration: Duration, future: F) -> Timeout<B, F> {
Timeout {
future,
sleep: self.sleep(duration),
}
}
pub fn accept(&self, listener: Handle) -> Accept<B> {
Accept {
shared: self.shared.clone(),
listener,
key: None,
}
}
pub fn spawn_local<F: Future + 'static>(&self, future: F) -> Result<JoinHandle<F::Output>> {
if self.shared.closed.get() {
return Err(Error::new(ErrorKind::NotFound));
}
let index = self
.shared
.occupied
.borrow()
.iter()
.position(|&v| !v)
.ok_or(Error::new(ErrorKind::ResourceLimit))?;
let wake = Arc::new(TaskWake {
ready: AtomicBool::new(true),
cancelled: AtomicBool::new(false),
notifier: self.shared.driver.borrow().notifier(),
});
let result = Rc::new(RefCell::new(JoinState {
value: None,
waker: None,
finished: false,
cancelled: false,
}));
let output = JoinGuard(result.clone());
let wrapped = async move {
let value = future.await;
let waker = {
let mut result = output.0.borrow_mut();
result.value = Some(value);
result.finished = true;
result.waker.take()
};
if let Some(waker) = waker {
waker.wake();
}
};
self.shared.occupied.borrow_mut()[index] = true;
self.shared.tasks.borrow_mut()[index] = Some(Task {
future: Box::pin(wrapped),
wake: wake.clone(),
});
Ok(JoinHandle { result, wake })
}
}
struct JoinState<T> {
value: Option<T>,
waker: Option<Waker>,
finished: bool,
cancelled: bool,
}
struct JoinGuard<T>(Rc<RefCell<JoinState<T>>>);
impl<T> Drop for JoinGuard<T> {
fn drop(&mut self) {
let waker = {
let mut state = self.0.borrow_mut();
if state.finished {
return;
}
state.cancelled = true;
state.finished = true;
state.waker.take()
};
if let Some(waker) = waker {
waker.wake();
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum JoinError {
Cancelled,
}
pub struct JoinHandle<T> {
result: Rc<RefCell<JoinState<T>>>,
wake: Arc<TaskWake>,
}
impl<T> JoinHandle<T> {
pub fn is_finished(&self) -> bool {
self.result.borrow().finished
}
pub fn cancel(&self) {
self.wake.cancelled.store(true, Ordering::Release);
self.wake.wake_by_ref();
}
}
impl<T> Future for JoinHandle<T> {
type Output = std::result::Result<T, JoinError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut state = self.result.borrow_mut();
if let Some(value) = state.value.take() {
Poll::Ready(Ok(value))
} else if state.cancelled {
Poll::Ready(Err(JoinError::Cancelled))
} else {
if state
.waker
.as_ref()
.is_none_or(|w| !w.will_wake(cx.waker()))
{
state.waker = Some(cx.waker().clone());
}
Poll::Pending
}
}
}
impl<T> Drop for JoinHandle<T> {
fn drop(&mut self) {
if !self.result.borrow().finished {
self.cancel();
}
}
}
pub struct AsyncIo<B: Backend> {
shared: Rc<Shared<B>>,
handle: Handle,
peer: Option<SocketAddr>,
read: Option<Key>,
write: Option<Key>,
shutdown: Option<Key>,
write_shut: bool,
closed: bool,
}
impl<B: Backend> Unpin for AsyncIo<B> {}
impl<B: Backend> AsyncIo<B> {
pub fn handle(&self) -> Handle {
self.handle
}
pub fn executor(&self) -> ExecutorHandle<B> {
ExecutorHandle {
shared: self.shared.clone(),
}
}
pub fn is_write_shut(&self) -> bool {
self.write_shut
}
pub fn poll_shutdown(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
if self.write_shut {
return Poll::Ready(Ok(()));
}
if self.closed {
return Poll::Ready(Err(io::ErrorKind::NotConnected.into()));
}
if self.peer.is_some() {
return Poll::Ready(Err(io::Error::new(
io::ErrorKind::Unsupported,
"a datagram adapter has no stream write direction to shut down",
)));
}
std::task::ready!(Pin::new(&mut *self).poll_flush(cx))?;
let key = match self.shutdown {
Some(key) => key,
None => {
let key = self.shared.reserve(cx).map_err(io_error)?;
let result = self
.shared
.driver
.borrow_mut()
.shutdown(self.handle, key.token());
match result {
Ok(op) => {
self.shared.slots.borrow_mut()[key.index].op = Some(op);
self.shutdown = Some(key);
key
}
Err(e) => {
self.shared.free(key);
return Poll::Ready(Err(shutdown_error(e)));
}
}
}
};
let Some(result) = self.shared.result(key, cx) else {
return Poll::Pending;
};
self.shared.free(key);
self.shutdown = None;
Poll::Ready(match result {
OpResult::Shutdown => {
self.write_shut = true;
Ok(())
}
OpResult::Err(e) => Err(shutdown_error(e)),
_ => Err(io_error(Error::new(ErrorKind::Cancelled))),
})
}
fn start_read(&mut self, cx: &Context<'_>, length: usize) -> Result<Key> {
let key = self.shared.reserve(cx)?;
let buf = {
let mut slots = self.shared.slots.borrow_mut();
let bytes = &mut slots[key.index].bytes;
let len = length.min(bytes.len());
ReadBuf::Provided(unsafe { IoBufMut::from_raw_parts(bytes.as_mut_ptr(), len) })
};
let result = if self.peer.is_some() {
self.shared
.driver
.borrow_mut()
.recv(self.handle, buf, key.token())
} else {
self.shared
.driver
.borrow_mut()
.read(self.handle, buf, key.token())
};
match result {
Ok(op) => {
self.shared.slots.borrow_mut()[key.index].op = Some(op);
Ok(key)
}
Err(e) => {
self.shared.free(key);
Err(e)
}
}
}
}
fn io_error(error: Error) -> io::Error {
if let Some(os) = error.os {
io::Error::from_raw_os_error(os)
} else {
io::Error::other(error)
}
}
fn shutdown_error(error: Error) -> io::Error {
match (error.os, error.kind) {
(None, ErrorKind::Unsupported) => io::Error::new(io::ErrorKind::Unsupported, error),
(None, ErrorKind::InvalidInput) => io::Error::new(io::ErrorKind::InvalidInput, error),
(None, ErrorKind::BrokenPipe) => io::Error::new(io::ErrorKind::BrokenPipe, error),
(None, ErrorKind::ConnectionReset) => io::Error::new(io::ErrorKind::ConnectionReset, error),
_ => io_error(error),
}
}
impl<B: Backend> AsyncRead for AsyncIo<B> {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
let this = self.get_mut();
if buf.is_empty() {
return Poll::Ready(Ok(0));
}
let key = match this.read {
Some(key) => key,
None => match this.start_read(cx, buf.len()) {
Ok(key) => {
this.read = Some(key);
key
}
Err(e) => return Poll::Ready(Err(io_error(e))),
},
};
let Some(result) = this.shared.result(key, cx) else {
return Poll::Pending;
};
match result {
OpResult::Read { n, .. } | OpResult::RecvFrom { n, .. } => {
let remaining = {
let mut slots = this.shared.slots.borrow_mut();
let slot = &mut slots[key.index];
let take = buf.len().min(n - slot.offset);
buf[..take].copy_from_slice(&slot.bytes[slot.offset..slot.offset + take]);
slot.offset += take;
if slot.offset < n {
slot.result = Some(OpResult::Read { n, lease: None });
}
(take, slot.offset == n)
};
if remaining.1 {
this.shared.free(key);
this.read = None;
}
Poll::Ready(Ok(remaining.0))
}
other => {
this.shared.free(key);
this.read = None;
Poll::Ready(match other {
OpResult::Eof => Ok(0),
OpResult::Err(e) => Err(io_error(e)),
OpResult::Cancelled => Err(io_error(Error::new(ErrorKind::Cancelled))),
_ => Err(io::Error::other("unexpected read completion")),
})
}
}
}
}
impl<B: Backend> AsyncWrite for AsyncIo<B> {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
if self.closed || self.write_shut || self.shutdown.is_some() {
return Poll::Ready(Err(io_error(Error::new(ErrorKind::BrokenPipe))));
}
match self.as_mut().poll_flush(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
Poll::Ready(Ok(())) => {}
}
if buf.is_empty() {
return Poll::Ready(Ok(0));
}
let this = self.get_mut();
let key = match this.shared.reserve(cx) {
Ok(key) => key,
Err(e) => return Poll::Ready(Err(io_error(e))),
};
let (ptr, n, too_big) = {
let mut slots = this.shared.slots.borrow_mut();
let bytes = &mut slots[key.index].bytes;
let n = buf.len().min(bytes.len());
bytes[..n].copy_from_slice(&buf[..n]);
(bytes.as_ptr(), n, n < buf.len() && this.peer.is_some())
};
if too_big {
this.shared.free(key);
return Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"datagram exceeds executor buffer",
)));
}
let buf = WriteBuf::Provided(unsafe { IoBuf::from_raw_parts(ptr, n) });
let result = if let Some(peer) = this.peer {
this.shared
.driver
.borrow_mut()
.send_to(this.handle, buf, peer, key.token())
} else {
this.shared
.driver
.borrow_mut()
.write(this.handle, buf, key.token())
};
match result {
Ok(op) => {
this.shared.slots.borrow_mut()[key.index].op = Some(op);
this.write = Some(key);
Poll::Ready(Ok(n))
}
Err(e) => {
this.shared.free(key);
Poll::Ready(Err(io_error(e)))
}
}
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
let this = self.get_mut();
let Some(key) = this.write else {
return Poll::Ready(Ok(()));
};
let Some(result) = this.shared.result(key, cx) else {
return Poll::Pending;
};
this.shared.free(key);
this.write = None;
Poll::Ready(match result {
OpResult::Wrote(_) => Ok(()),
OpResult::Err(e) => Err(io_error(e)),
_ => Err(io::Error::other("write cancelled")),
})
}
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
match self.as_mut().poll_flush(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
Poll::Ready(Ok(())) => {}
}
let this = self.get_mut();
if !this.closed {
this.shared
.driver
.borrow_mut()
.close(this.handle, INTERNAL)
.map_err(io_error)?;
this.closed = true;
}
Poll::Ready(Ok(()))
}
}
impl<B: Backend> Drop for AsyncIo<B> {
fn drop(&mut self) {
if let Some(key) = self.read.take() {
self.shared.abandon(key);
}
if let Some(key) = self.write.take() {
self.shared.abandon(key);
}
if let Some(key) = self.shutdown.take() {
self.shared.abandon(key);
}
if !self.closed {
let _ = self.shared.driver.borrow_mut().close(self.handle, INTERNAL);
}
}
}
pub struct Sleep<B: Backend> {
shared: Rc<Shared<B>>,
deadline: Instant,
key: Option<Key>,
done: bool,
}
impl<B: Backend> Unpin for Sleep<B> {}
impl<B: Backend> Future for Sleep<B> {
type Output = Result<()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
if this.done {
return Poll::Ready(Ok(()));
}
let key = match this.key {
Some(key) => key,
None => {
let key = this.shared.reserve(cx)?;
let timer = this
.shared
.driver
.borrow_mut()
.timer(this.deadline, None, key.token());
match timer {
Ok(timer) => {
let op = this.shared.driver.borrow().timer_op(timer);
let mut slots = this.shared.slots.borrow_mut();
slots[key.index].op = op;
slots[key.index].timer = Some(timer);
this.key = Some(key);
key
}
Err(e) => {
this.shared.free(key);
return Poll::Ready(Err(e));
}
}
}
};
let Some(result) = this.shared.result(key, cx) else {
return Poll::Pending;
};
this.shared.free(key);
this.key = None;
this.done = true;
Poll::Ready(match result {
OpResult::Timer => Ok(()),
OpResult::Err(e) => Err(e),
_ => Err(Error::new(ErrorKind::Cancelled)),
})
}
}
impl<B: Backend> Drop for Sleep<B> {
fn drop(&mut self) {
if let Some(key) = self.key.take() {
self.shared.abandon(key);
}
}
}
pub struct Timeout<B: Backend, F> {
future: F,
sleep: Sleep<B>,
}
impl<B: Backend, F: Future> Future for Timeout<B, F> {
type Output = Result<F::Output>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = unsafe { self.get_unchecked_mut() };
if let Poll::Ready(value) = unsafe { Pin::new_unchecked(&mut this.future) }.poll(cx) {
return Poll::Ready(Ok(value));
}
match Pin::new(&mut this.sleep).poll(cx) {
Poll::Ready(Ok(())) => Poll::Ready(Err(Error::new(ErrorKind::TimedOut))),
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
Poll::Pending => Poll::Pending,
}
}
}
pub struct Accept<B: Backend> {
shared: Rc<Shared<B>>,
listener: Handle,
key: Option<Key>,
}
pub struct Connect<B: Backend> {
executor: ExecutorHandle<B>,
address: SocketAddr,
opts: TcpOpts,
key: Option<Key>,
handle: Option<Handle>,
}
pub struct Resolve<B: Backend> {
executor: ExecutorHandle<B>,
request: Option<DnsRequest>,
key: Option<Key>,
}
impl<B: Backend> Unpin for Resolve<B> {}
impl<B: Backend> Future for Resolve<B> {
type Output = Result<Vec<SocketAddr>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let shared = &this.executor.shared;
let key = match this.key {
Some(key) => key,
None => {
if this.request.is_none() {
return Poll::Ready(Err(Error::new(ErrorKind::InvalidInput)));
}
let key = shared.reserve(cx)?;
let request = this
.request
.take()
.ok_or(Error::new(ErrorKind::InvalidInput))?;
let result = shared.driver.borrow_mut().resolve(request, key.token());
match result {
Ok(op) => {
shared.slots.borrow_mut()[key.index].op = Some(op);
this.key = Some(key);
key
}
Err(e) => {
shared.free(key);
return Poll::Ready(Err(e));
}
}
}
};
let Some(result) = shared.result(key, cx) else {
return Poll::Pending;
};
shared.free(key);
this.key = None;
Poll::Ready(match result {
OpResult::Resolved(addresses) => Ok(addresses),
OpResult::Err(e) => Err(e),
_ => Err(Error::new(ErrorKind::Cancelled)),
})
}
}
impl<B: Backend> Drop for Resolve<B> {
fn drop(&mut self) {
if let Some(key) = self.key.take() {
self.executor.shared.abandon(key);
}
}
}
pub struct Close<B: Backend> {
executor: ExecutorHandle<B>,
handle: Option<Handle>,
key: Option<Key>,
}
impl<B: Backend> Unpin for Close<B> {}
impl<B: Backend> Future for Close<B> {
type Output = Result<()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let shared = &this.executor.shared;
let key = if let Some(key) = this.key {
key
} else {
let key = shared.reserve(cx)?;
let Some(handle) = this.handle.take() else {
shared.free(key);
return Poll::Ready(Err(Error::new(ErrorKind::InvalidInput)));
};
let result = {
let mut driver = shared.driver.borrow_mut();
if driver.is_closing(handle) {
Ok(())
} else {
driver.close(handle, INTERNAL)
}
};
if let Err(e) = result {
shared.free(key);
return Poll::Ready(if e.kind == ErrorKind::NotFound {
Ok(())
} else {
Err(e)
});
}
shared.slots.borrow_mut()[key.index].closing = Some(handle);
this.key = Some(key);
key
};
let Some(result) = shared.result(key, cx) else {
return Poll::Pending;
};
shared.free(key);
this.key = None;
Poll::Ready(match result {
OpResult::Closed => Ok(()),
OpResult::Err(e) => Err(e),
_ => Err(Error::new(ErrorKind::Other)),
})
}
}
impl<B: Backend> Drop for Close<B> {
fn drop(&mut self) {
if let Some(key) = self.key.take() {
self.executor.shared.abandon(key);
}
}
}
pub struct Blocking<B: Backend> {
executor: ExecutorHandle<B>,
work: Option<Box<dyn FnOnce() -> BlockingResult + Send>>,
key: Option<Key>,
}
impl<B: Backend> Unpin for Blocking<B> {}
impl<B: Backend> Future for Blocking<B> {
type Output = Result<Payload>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let shared = &this.executor.shared;
let key = match this.key {
Some(key) => key,
None => {
if this.work.is_none() {
return Poll::Ready(Err(Error::new(ErrorKind::InvalidInput)));
}
let key = shared.reserve(cx)?;
let request = this
.work
.take()
.ok_or(Error::new(ErrorKind::InvalidInput))?;
let result = shared.driver.borrow_mut().blocking(request, key.token());
match result {
Ok(op) => {
shared.slots.borrow_mut()[key.index].op = Some(op);
this.key = Some(key);
key
}
Err(e) => {
shared.free(key);
return Poll::Ready(Err(e));
}
}
}
};
let Some(result) = shared.result(key, cx) else {
return Poll::Pending;
};
shared.free(key);
this.key = None;
Poll::Ready(match result {
OpResult::Blocking(addresses) => Ok(addresses),
OpResult::Err(e) => Err(e),
_ => Err(Error::new(ErrorKind::Cancelled)),
})
}
}
impl<B: Backend> Drop for Blocking<B> {
fn drop(&mut self) {
if let Some(key) = self.key.take() {
self.executor.shared.abandon(key);
}
}
}
impl<B: Backend> Unpin for Connect<B> {}
impl<B: Backend> Future for Connect<B> {
type Output = Result<AsyncIo<B>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let shared = &this.executor.shared;
let key = match this.key {
Some(key) => key,
None => {
let key = shared.reserve(cx)?;
let result =
shared
.driver
.borrow_mut()
.tcp_connect(this.address, &this.opts, key.token());
match result {
Ok(handle) => {
this.handle = Some(handle);
this.key = Some(key);
key
}
Err(error) => {
shared.free(key);
return Poll::Ready(Err(error));
}
}
}
};
let Some(result) = shared.result(key, cx) else {
return Poll::Pending;
};
shared.free(key);
this.key = None;
Poll::Ready(match result {
OpResult::Connected => Ok(this
.executor
.io(this.handle.take().expect("connected handle"))),
OpResult::Err(error) => Err(error),
_ => Err(Error::new(ErrorKind::Cancelled)),
})
}
}
impl<B: Backend> Drop for Connect<B> {
fn drop(&mut self) {
if let Some(handle) = self.handle.take() {
let _ = self
.executor
.shared
.driver
.borrow_mut()
.close(handle, INTERNAL);
}
if let Some(key) = self.key.take() {
self.executor.shared.abandon(key);
}
}
}
impl<B: Backend> Unpin for Accept<B> {}
impl<B: Backend> Future for Accept<B> {
type Output = Result<AsyncIo<B>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let key = match this.key {
Some(key) => key,
None => {
let key = this.shared.reserve(cx)?;
let result = this
.shared
.driver
.borrow_mut()
.accept(this.listener, key.token());
match result {
Ok(op) => {
this.shared.slots.borrow_mut()[key.index].op = Some(op);
this.key = Some(key);
key
}
Err(e) => {
this.shared.free(key);
return Poll::Ready(Err(e));
}
}
}
};
let Some(result) = this.shared.result(key, cx) else {
return Poll::Pending;
};
this.shared.free(key);
this.key = None;
Poll::Ready(match result {
OpResult::Accepted { conn, .. } | OpResult::PipeAccepted { conn } => {
Ok(ExecutorHandle {
shared: this.shared.clone(),
}
.io(conn))
}
OpResult::Err(e) => Err(e),
_ => Err(Error::new(ErrorKind::Cancelled)),
})
}
}
impl<B: Backend> Drop for Accept<B> {
fn drop(&mut self) {
if let Some(key) = self.key.take() {
self.shared.abandon(key);
}
}
}
#[cfg(turnloop_backend = "web")]
impl ExecutorHandle<crate::backend::web::Web> {
pub fn fetch(&self, url: &str) -> Fetch {
Fetch {
executor: self.clone(),
url: url.into(),
key: None,
handle: None,
}
}
}
#[cfg(turnloop_backend = "web")]
pub struct Fetch {
executor: ExecutorHandle<crate::backend::web::Web>,
url: String,
key: Option<Key>,
handle: Option<Handle>,
}
#[cfg(turnloop_backend = "web")]
impl Future for Fetch {
type Output = Result<Vec<u8>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let shared = &this.executor.shared;
let key = match this.key {
Some(key) => key,
None => {
let key = shared.reserve(cx)?;
let buf = {
let mut slots = shared.slots.borrow_mut();
let bytes = &mut slots[key.index].bytes;
ReadBuf::Provided(unsafe {
IoBufMut::from_raw_parts(bytes.as_mut_ptr(), bytes.len())
})
};
let result = shared
.driver
.borrow_mut()
.fetch(&this.url, buf, key.token());
match result {
Ok((handle, op)) => {
shared.slots.borrow_mut()[key.index].op = Some(op);
this.handle = Some(handle);
this.key = Some(key);
key
}
Err(e) => {
shared.free(key);
return Poll::Ready(Err(e));
}
}
}
};
let Some(result) = shared.result(key, cx) else {
return Poll::Pending;
};
let result = match result {
OpResult::Read { n, .. } => Ok(shared.slots.borrow()[key.index].bytes[..n].to_vec()),
OpResult::Err(e) => Err(e),
_ => Err(Error::new(ErrorKind::Cancelled)),
};
shared.free(key);
this.key = None;
Poll::Ready(result)
}
}
#[cfg(turnloop_backend = "web")]
impl Drop for Fetch {
fn drop(&mut self) {
if let Some(key) = self.key.take() {
self.executor.shared.abandon(key);
}
if let Some(handle) = self.handle.take() {
let _ = self.executor.driver().close(handle, INTERNAL);
}
}
}