xitca-http 0.9.0

http library for xitca
Documentation
use core::{
    cell::RefCell,
    future::poll_fn,
    task::{Poll, Waker},
};

use std::{io, rc::Rc};

use xitca_io::io::{AsyncBufRead, AsyncBufWrite, BoundedBuf};

use crate::bytes::BytesMut;

pub(super) trait BufIo {
    fn read(self, io: &impl AsyncBufRead) -> impl Future<Output = (io::Result<usize>, Self)>;

    fn write(self, io: &impl AsyncBufWrite) -> impl Future<Output = (io::Result<()>, Self)>;
}

impl BufIo for BytesMut {
    async fn read(mut self, io: &impl AsyncBufRead) -> (io::Result<usize>, Self) {
        let len = self.len();

        self.reserve(4096);

        let (res, buf) = io.read(self.slice(len..)).await;
        (res, buf.into_inner())
    }

    async fn write(self, io: &impl AsyncBufWrite) -> (io::Result<()>, Self) {
        let (res, mut buf) = io.write_all(self).await;
        buf.clear();
        (res, buf)
    }
}

pub(super) struct SharedIo<Io> {
    inner: Rc<_SharedIo<Io>>,
}

struct _SharedIo<Io> {
    io: Io,
    notify: RefCell<Inner<BytesMut>>,
}

impl<Io> SharedIo<Io> {
    pub(super) fn new(io: Io) -> Self {
        Self {
            inner: Rc::new(_SharedIo {
                io,
                notify: RefCell::new(Inner { waker: None, val: None }),
            }),
        }
    }

    #[inline(always)]
    pub(super) fn io(&self) -> &Io {
        &self.inner.io
    }

    pub(super) fn into_io(self) -> Io {
        Rc::try_unwrap(self.inner)
            .ok()
            .expect("SharedIo still has outstanding references")
            .io
    }

    pub(super) fn notifier(&mut self) -> NotifierIo<Io> {
        NotifierIo {
            inner: self.inner.clone(),
        }
    }

    pub(super) fn wait(&mut self) -> impl Future<Output = Option<BytesMut>> {
        poll_fn(|cx| {
            let mut inner = self.inner.notify.borrow_mut();
            if let Some(val) = inner.val.take() {
                return Poll::Ready(Some(val));
            } else if Rc::strong_count(&self.inner) == 1 {
                return Poll::Ready(None);
            }
            inner.waker = Some(cx.waker().clone());
            Poll::Pending
        })
    }
}

pub(super) struct NotifierIo<Io> {
    inner: Rc<_SharedIo<Io>>,
}

impl<Io> Drop for NotifierIo<Io> {
    fn drop(&mut self) {
        if let Some(waker) = self.inner.notify.borrow_mut().waker.take() {
            waker.wake();
        }
    }
}

impl<Io> NotifierIo<Io> {
    pub(super) fn io(&self) -> &Io {
        &self.inner.io
    }

    pub(super) fn notify(&mut self, val: BytesMut) {
        self.inner.notify.borrow_mut().val = Some(val);
    }
}

struct Inner<V> {
    waker: Option<Waker>,
    val: Option<V>,
}