sliceable-ring-buffer 0.1.0

A double-ended queue that Deref's into a slice.
Documentation
use super::SliceRingBuffer;
use std::{
    io,
    pin::Pin,
    task::{Context, Poll},
};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};

impl AsyncRead for SliceRingBuffer<u8> {
    fn poll_read(mut self: Pin<&mut Self>, _cx: &mut Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<io::Result<()>> {
        let available_data = self.as_slice();
        let len_to_copy = available_data.len().min(buf.remaining());
        buf.put_slice(&available_data[..len_to_copy]);
        self.move_head(len_to_copy as isize);
        Poll::Ready(Ok(()))
    }
}

impl AsyncWrite for SliceRingBuffer<u8> {
    fn poll_write(mut self: Pin<&mut Self>, _cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize, io::Error>> {
        self.reserve(buf.len());
        let uninit_slice = self.uninit_slice();
        unsafe {
            let dst_ptr = uninit_slice.as_mut_ptr().cast::<u8>();
            std::ptr::copy_nonoverlapping(buf.as_ptr(), dst_ptr, buf.len());
        }
        self.move_tail(buf.len() as isize);
        Poll::Ready(Ok(buf.len()))
    }

    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> { Poll::Ready(Ok(())) }

    fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> { Poll::Ready(Ok(())) }
}

#[cfg(all(test, feature = "tokio-io"))]
mod tokio_tests {
    use super::SliceRingBuffer;
    use tokio::io::{AsyncReadExt, AsyncWriteExt};

    #[tokio::test]
    async fn test_async_read() {
        let mut buf = SliceRingBuffer::from(b"async read test".to_vec());
        let mut dest = Vec::new();

        let bytes_read = buf.read_to_end(&mut dest).await.unwrap();
        assert_eq!(bytes_read, 15);
        assert_eq!(dest, b"async read test");
        assert!(buf.is_empty());
    }

    #[tokio::test]
    async fn test_async_write() {
        let mut buf = SliceRingBuffer::<u8>::new();
        buf.write_all(b"async write").await.unwrap();
        assert_eq!(buf.as_slice(), b"async write");
    }

    #[tokio::test]
    async fn test_tokio_copy() {
        let mut source = SliceRingBuffer::from(b"async copy me".to_vec());
        let mut dest = SliceRingBuffer::<u8>::new();

        let bytes_copied = tokio::io::copy(&mut source, &mut dest).await.unwrap();
        assert_eq!(bytes_copied, 13);
        assert!(source.is_empty());
        assert_eq!(dest.as_slice(), b"async copy me");
    }
}