use core::pin::Pin;
use core::task::{Context, Poll};
use std::io;
use std::sync::Arc;
use futures_io::{AsyncRead, AsyncWrite};
use crate::sync::atomic_waker::AtomicWaker;
use crate::sync::internal::{AtomicBool, AtomicUsize, Ordering};
struct Pipe {
ring: Box<[core::cell::UnsafeCell<u8>]>,
written: AtomicUsize,
read: AtomicUsize,
reader: AtomicWaker,
writer: AtomicWaker,
write_closed: AtomicBool,
read_closed: AtomicBool,
}
unsafe impl Send for Pipe {}
unsafe impl Sync for Pipe {}
impl Pipe {
fn new(capacity: usize) -> Arc<Self> {
let capacity = capacity.max(1);
Arc::new(Self {
ring: (0..capacity)
.map(|_| core::cell::UnsafeCell::new(0))
.collect(),
written: AtomicUsize::new(0),
read: AtomicUsize::new(0),
reader: AtomicWaker::new(),
writer: AtomicWaker::new(),
write_closed: AtomicBool::new(false),
read_closed: AtomicBool::new(false),
})
}
fn base(&self) -> *mut u8 {
core::cell::UnsafeCell::raw_get(self.ring.as_ptr())
}
fn poll_read(&self, cx: &mut Context<'_>, out: &mut [u8]) -> Poll<io::Result<usize>> {
if out.is_empty() {
return Poll::Ready(Ok(0));
}
let read = self.read.load(Ordering::Relaxed);
let mut written = self.written.load(Ordering::Acquire);
if written == read {
if self.write_closed.load(Ordering::Acquire) {
return Poll::Ready(Ok(0));
}
self.reader.register(cx.waker());
written = self.written.load(Ordering::SeqCst);
if written == read {
if self.write_closed.load(Ordering::SeqCst) {
return Poll::Ready(Ok(0));
}
return Poll::Pending;
}
}
let n = (written - read).min(out.len());
let cap = self.ring.len();
let at = read % cap;
let first = n.min(cap - at);
unsafe {
core::ptr::copy_nonoverlapping(self.base().add(at), out.as_mut_ptr(), first);
core::ptr::copy_nonoverlapping(self.base(), out.as_mut_ptr().add(first), n - first);
}
self.read.store(read + n, Ordering::Release);
self.writer.wake();
Poll::Ready(Ok(n))
}
fn poll_write(&self, cx: &mut Context<'_>, input: &[u8]) -> Poll<io::Result<usize>> {
if self.read_closed.load(Ordering::Acquire) || self.write_closed.load(Ordering::Relaxed) {
return Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()));
}
if input.is_empty() {
return Poll::Ready(Ok(0));
}
let cap = self.ring.len();
let written = self.written.load(Ordering::Relaxed);
let mut read = self.read.load(Ordering::Acquire);
if written - read == cap {
self.writer.register(cx.waker());
read = self.read.load(Ordering::SeqCst);
if written - read == cap {
if self.read_closed.load(Ordering::SeqCst) {
return Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()));
}
return Poll::Pending;
}
}
let n = (cap - (written - read)).min(input.len());
let at = written % cap;
let first = n.min(cap - at);
unsafe {
core::ptr::copy_nonoverlapping(input.as_ptr(), self.base().add(at), first);
core::ptr::copy_nonoverlapping(input.as_ptr().add(first), self.base(), n - first);
}
self.written.store(written + n, Ordering::Release);
self.reader.wake();
Poll::Ready(Ok(n))
}
fn close_write(&self) {
self.write_closed.store(true, Ordering::SeqCst);
self.reader.wake();
}
fn close_read(&self) {
self.read_closed.store(true, Ordering::SeqCst);
self.writer.wake();
}
}
pub struct DuplexStream {
read: Arc<Pipe>,
write: Arc<Pipe>,
}
pub fn duplex(max_buf_size: usize) -> (DuplexStream, DuplexStream) {
let (ab, ba) = (Pipe::new(max_buf_size), Pipe::new(max_buf_size));
(
DuplexStream {
read: Arc::clone(&ba),
write: Arc::clone(&ab),
},
DuplexStream {
read: ab,
write: ba,
},
)
}
impl AsyncRead for DuplexStream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
crate::coop::poll_budget(cx, |cx| self.read.poll_read(cx, buf))
}
}
impl AsyncWrite for DuplexStream {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
crate::coop::poll_budget(cx, |cx| self.write.poll_write(cx, buf))
}
fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
self.write.close_write();
Poll::Ready(Ok(()))
}
}
impl Drop for DuplexStream {
fn drop(&mut self) {
self.write.close_write();
self.read.close_read();
}
}
impl core::fmt::Debug for DuplexStream {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("DuplexStream").finish_non_exhaustive()
}
}
pub struct SimplexReader {
pipe: Arc<Pipe>,
}
pub struct SimplexWriter {
pipe: Arc<Pipe>,
}
pub fn simplex(max_buf_size: usize) -> (SimplexReader, SimplexWriter) {
let pipe = Pipe::new(max_buf_size);
(
SimplexReader {
pipe: Arc::clone(&pipe),
},
SimplexWriter { pipe },
)
}
impl AsyncRead for SimplexReader {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
crate::coop::poll_budget(cx, |cx| self.pipe.poll_read(cx, buf))
}
}
impl AsyncWrite for SimplexWriter {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
crate::coop::poll_budget(cx, |cx| self.pipe.poll_write(cx, buf))
}
fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
self.pipe.close_write();
Poll::Ready(Ok(()))
}
}
impl Drop for SimplexReader {
fn drop(&mut self) {
self.pipe.close_read();
}
}
impl Drop for SimplexWriter {
fn drop(&mut self) {
self.pipe.close_write();
}
}
impl core::fmt::Debug for SimplexReader {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SimplexReader").finish_non_exhaustive()
}
}
impl core::fmt::Debug for SimplexWriter {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SimplexWriter").finish_non_exhaustive()
}
}