use core::pin::Pin;
use core::task::{Context, Poll};
pub fn escape_ascii(input: &[u8]) -> String {
let mut result = String::new();
for byte in input {
for ascii_byte in std::ascii::escape_default(*byte) {
result.push_str(std::str::from_utf8(&[ascii_byte]).unwrap());
}
}
result
}
pub trait MemBlock {
fn u8slice(&self) -> &[u8];
fn mut_u8slice(&mut self) -> &mut [u8];
}
impl MemBlock for &mut [u8] {
fn u8slice(&self) -> &[u8] {
&self[..]
}
fn mut_u8slice(&mut self) -> &mut [u8] {
&mut self[..]
}
}
macro_rules! generate_mem_block_impls {
( $( $LEN:expr , )+ ) => {
$(
impl MemBlock for [u8; $LEN] {
fn u8slice(&self) -> &[u8] {
&self[..]
}
fn mut_u8slice(&mut self) -> &mut [u8] {
&mut self[..]
}
}
impl MemBlock for Box<[u8; $LEN]> {
fn u8slice(&self) -> &[u8] {
&self.as_ref()[..]
}
fn mut_u8slice(&mut self) -> &mut [u8] {
&mut self.as_mut()[..]
}
}
)+
}
}
generate_mem_block_impls! {
8, 16, 32, 64, 100, 128, 200, 256, 512,
1024, 2 * 1024, 4 * 1024, 8 * 1024, 16 * 1024, 32 * 1024,
64 * 1024, 128 * 1024, 256 * 1024, 512 * 1024, 1024 * 1024,
}
pub trait OwnedMemBlock: MemBlock {
fn new() -> Self;
}
macro_rules! generate_owned_mem_block_impls {
( $( $LEN:expr , )+ ) => {
$(
impl OwnedMemBlock for [u8; $LEN] {
fn new() -> Self {
[0u8; $LEN]
}
}
impl OwnedMemBlock for Box<[u8; $LEN]> {
fn new() -> Self {
Box::new([0u8; $LEN])
}
}
)+
}
}
generate_owned_mem_block_impls! {
8, 16, 32, 64, 100, 128, 200, 256, 512,
1024, 2 * 1024, 4 * 1024, 8 * 1024, 16 * 1024, 32 * 1024,
64 * 1024, 128 * 1024, 256 * 1024, 512 * 1024, 1024 * 1024,
}
#[derive(Clone, Eq, Hash, PartialEq)]
pub struct FixedBuf<T: MemBlock> {
mem: T,
read_index: usize,
write_index: usize,
}
impl FixedBuf<&mut [u8]> {
pub fn new_with_slice(mem: &mut [u8]) -> FixedBuf<&mut [u8]> {
FixedBuf {
mem,
write_index: 0,
read_index: 0,
}
}
}
impl<T: OwnedMemBlock> Default for FixedBuf<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: OwnedMemBlock> FixedBuf<T> {
pub fn new() -> Self {
Self {
mem: T::new(),
write_index: 0,
read_index: 0,
}
}
pub fn new_with_mem(mem: T) -> Self {
Self {
mem,
write_index: 0,
read_index: 0,
}
}
pub fn into_inner(self) -> T {
self.mem
}
}
impl<T: MemBlock> FixedBuf<T> {
pub fn len(&self) -> usize {
self.write_index - self.read_index
}
pub fn capacity(&self) -> usize {
self.mem.u8slice().len()
}
pub fn is_empty(&self) -> bool {
self.write_index == self.read_index
}
pub fn write_str(&mut self, s: &str) -> std::io::Result<()> {
self.write_bytes(s.as_bytes()).map(|_| ())
}
pub fn write_bytes(&mut self, data: &[u8]) -> std::io::Result<usize> {
let writable = self.writable().ok_or_else(|| {
std::io::Error::new(std::io::ErrorKind::InvalidData, "end of buffer full")
})?;
if writable.len() < data.len() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Not enough free space in buffer",
));
}
let dest = &mut writable[..data.len()];
dest.copy_from_slice(data);
self.wrote(data.len());
Ok(data.len())
}
pub fn writable(&mut self) -> Option<&mut [u8]> {
if self.write_index >= self.mem.u8slice().len() {
return None;
}
Some(&mut self.mem.mut_u8slice()[self.write_index..])
}
pub fn wrote(&mut self, num_bytes: usize) {
if num_bytes == 0 {
return;
}
let new_write_index = self.write_index + num_bytes;
if new_write_index > self.mem.u8slice().len() {
panic!("write would overflow");
}
self.write_index = new_write_index;
}
pub fn readable(&self) -> &[u8] {
&self.mem.u8slice()[self.read_index..self.write_index]
}
pub fn read_bytes(&mut self, num_bytes: usize) -> &[u8] {
let new_read_index = self.read_index + num_bytes;
if new_read_index > self.write_index {
panic!("read would underflow");
}
let old_read_index = self.read_index;
self.read_index = new_read_index;
if self.read_index == self.write_index {
self.write_index = 0;
self.read_index = 0;
}
&self.mem.u8slice()[old_read_index..new_read_index]
}
pub fn read_all(&mut self) -> &[u8] {
self.read_bytes(self.len())
}
pub fn read_and_copy_bytes(&mut self, dest: &mut [u8]) -> std::io::Result<usize> {
let readable = self.readable();
let len = core::cmp::min(dest.len(), readable.len());
if len == 0 {
return Ok(0);
}
let src = &readable[..len];
let copy_dest = &mut dest[..len];
copy_dest.copy_from_slice(src);
self.read_bytes(len);
Ok(len)
}
pub async fn read_delimited<R>(&mut self, mut input: R, delim: &[u8]) -> std::io::Result<&[u8]>
where
R: tokio::io::AsyncRead + std::marker::Unpin + Send,
{
loop {
if let Some(delim_index) = self
.readable()
.windows(delim.len())
.enumerate()
.filter(|(_index, window)| *window == delim)
.map(|(index, _window)| index)
.next()
{
let result_start = self.read_index;
let result_end = self.read_index + delim_index;
self.read_bytes(delim_index + delim.len());
return Ok(&self.mem.u8slice()[result_start..result_end]);
}
self.shift();
let writable = self.writable().ok_or_else(|| {
std::io::Error::new(std::io::ErrorKind::InvalidData, "end of buffer full")
})?;
let num_bytes_read = tokio::io::AsyncReadExt::read(&mut input, writable).await?;
if num_bytes_read == 0 {
if self.read_index == 0 {
return Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"eof with no data read",
));
}
return Err(std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
"eof before delim read",
));
}
self.wrote(num_bytes_read);
}
}
pub fn shift(&mut self) {
if self.read_index == 0 {
return;
}
if self.read_index == self.write_index {
self.write_index = 0;
self.read_index = 0;
return;
}
self.mem
.mut_u8slice()
.copy_within(self.read_index..self.write_index, 0);
self.write_index -= self.read_index;
self.read_index = 0;
}
}
impl<T: MemBlock> std::io::Write for FixedBuf<T> {
fn write(&mut self, data: &[u8]) -> std::io::Result<usize> {
self.write_bytes(data)
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl<T: MemBlock> std::io::Read for FixedBuf<T> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.read_and_copy_bytes(buf)
}
}
impl<T: MemBlock + Unpin> tokio::io::AsyncWrite for FixedBuf<T> {
fn poll_write(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<Result<usize, std::io::Error>> {
Poll::Ready(self.get_mut().write_bytes(buf))
}
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {
Poll::Ready(Ok(()))
}
fn poll_shutdown(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
) -> Poll<Result<(), std::io::Error>> {
Poll::Ready(Ok(()))
}
}
impl<T: MemBlock + Unpin> tokio::io::AsyncRead for FixedBuf<T> {
fn poll_read(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &mut tokio::io::ReadBuf<'_>,
) -> Poll<Result<(), std::io::Error>> {
Poll::Ready(
self.get_mut()
.read_and_copy_bytes(buf.initialize_unfilled())
.map(|n| buf.advance(n)),
)
}
}
impl<T: MemBlock> std::fmt::Debug for FixedBuf<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"FixedBuf{{{} writable, {} readable: \"{}\"}}",
self.capacity() - self.write_index,
self.len(),
escape_ascii(self.readable())
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_array_sizes() {
let _: FixedBuf<[u8; 8]> = FixedBuf::new();
let _: FixedBuf<[u8; 16]> = FixedBuf::new();
let _: FixedBuf<[u8; 32]> = FixedBuf::new();
let _: FixedBuf<[u8; 64]> = FixedBuf::new();
let _: FixedBuf<[u8; 100]> = FixedBuf::new();
let _: FixedBuf<[u8; 128]> = FixedBuf::new();
let _: FixedBuf<[u8; 200]> = FixedBuf::new();
let _: FixedBuf<[u8; 256]> = FixedBuf::new();
let _: FixedBuf<[u8; 512]> = FixedBuf::new();
let _: FixedBuf<[u8; 1024]> = FixedBuf::new();
let _: FixedBuf<[u8; 2 * 1024]> = FixedBuf::new();
let _: FixedBuf<[u8; 4 * 1024]> = FixedBuf::new();
let _: FixedBuf<[u8; 8 * 1024]> = FixedBuf::new();
let _: FixedBuf<[u8; 16 * 1024]> = FixedBuf::new();
let _: FixedBuf<[u8; 32 * 1024]> = FixedBuf::new();
let _: FixedBuf<[u8; 64 * 1024]> = FixedBuf::new();
let _: FixedBuf<[u8; 128 * 1024]> = FixedBuf::new();
let _: FixedBuf<[u8; 256 * 1024]> = FixedBuf::new();
let _: FixedBuf<[u8; 512 * 1024]> = FixedBuf::new();
}
#[test]
fn test_box_array_sizes() {
let _: FixedBuf<Box<[u8; 8]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 16]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 32]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 64]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 100]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 128]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 200]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 256]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 512]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 1024]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 2 * 1024]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 4 * 1024]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 8 * 1024]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 16 * 1024]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 32 * 1024]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 64 * 1024]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 128 * 1024]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 256 * 1024]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 512 * 1024]>> = FixedBuf::new();
let _: FixedBuf<Box<[u8; 1024 * 1024]>> = FixedBuf::new();
}
#[test]
fn test_array_constructors() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
buf.write_str("abc").unwrap();
assert_eq!("abc", escape_ascii(buf.readable()));
let mem: [u8; 16] = buf.into_inner();
buf = FixedBuf::new_with_mem(mem);
assert_eq!("", escape_ascii(buf.readable()));
buf.wrote(3);
assert_eq!("abc", escape_ascii(buf.read_all()));
assert_eq!("", escape_ascii(buf.readable()));
}
#[test]
fn test_box_array_constructors() {
let mut buf: FixedBuf<Box<[u8; 16]>> = FixedBuf::new();
buf.write_str("abc").unwrap();
assert_eq!("abc", escape_ascii(buf.readable()));
let mem = buf.into_inner();
buf = FixedBuf::new_with_mem(mem);
assert_eq!("", escape_ascii(buf.readable()));
buf.wrote(3);
assert_eq!("abc", escape_ascii(buf.read_all()));
assert_eq!("", escape_ascii(buf.readable()));
}
#[test]
fn test_slice_constructor() {
let mut mem = [0u8; 15];
let mut buf = FixedBuf::new_with_slice(&mut mem);
buf.write_str("abc").unwrap();
assert_eq!("abc", escape_ascii(buf.readable()));
buf = FixedBuf::new_with_slice(&mut mem);
assert_eq!("", escape_ascii(buf.readable()));
buf.wrote(3);
assert_eq!("abc", escape_ascii(buf.read_all()));
assert_eq!("", escape_ascii(buf.readable()));
}
#[test]
fn empty() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
assert_eq!("", escape_ascii(buf.readable()));
assert_eq!("", escape_ascii(buf.read_all()));
buf.shift();
assert_eq!("", escape_ascii(buf.readable()));
assert_eq!("", escape_ascii(buf.read_all()));
}
#[test]
fn test_len() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
assert_eq!(0, buf.len());
buf.write_str("abc").unwrap();
assert_eq!(3, buf.len());
buf.read_bytes(2);
assert_eq!(1, buf.len());
buf.shift();
assert_eq!(1, buf.len());
buf.read_all();
assert_eq!(0, buf.len());
}
#[test]
fn test_write_str() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
buf.write_str("a").unwrap();
buf.write_str("b").unwrap();
assert_eq!("ab", escape_ascii(buf.readable()));
let many_cs = "c".repeat(13);
buf.write_str(&many_cs).unwrap();
buf.write_str("d").unwrap();
assert_eq!(
"ab".to_string() + &many_cs + "d",
escape_ascii(buf.readable())
);
buf.write_str("e").unwrap_err();
}
#[test]
fn test_writable_and_wrote() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
assert_eq!(16, buf.writable().unwrap().len());
buf.writable().unwrap()[0] = 'a' as u8;
buf.wrote(1);
assert_eq!("a", escape_ascii(buf.readable()));
let many_bs = "b".repeat(15);
assert_eq!(many_bs.len(), buf.writable().unwrap().len());
buf.writable().unwrap().copy_from_slice(many_bs.as_bytes());
buf.wrote(many_bs.len());
assert_eq!("a".to_string() + &many_bs, escape_ascii(buf.readable()));
assert_eq!(None, buf.writable());
}
#[test]
#[should_panic]
fn test_wrote_too_much() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
buf.wrote(17);
}
#[test]
fn test_readable_and_read() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
assert_eq!("", escape_ascii(buf.readable()));
buf.write_str("abc").unwrap();
assert_eq!("abc", escape_ascii(buf.readable()));
buf.read_bytes(1);
assert_eq!("bc", escape_ascii(buf.readable()));
buf.read_bytes(2);
assert_eq!("", escape_ascii(buf.readable()));
buf.write_str("d").unwrap();
assert_eq!("d", escape_ascii(buf.readable()));
buf.read_bytes(1);
assert_eq!("", escape_ascii(buf.readable()));
}
#[test]
#[should_panic]
fn test_read_too_much() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
buf.write_str("a").unwrap();
buf.read_bytes(2);
}
#[test]
fn test_read_all() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
assert_eq!("", escape_ascii(buf.read_all()));
buf.write_str("abc").unwrap();
assert_eq!("abc", escape_ascii(buf.read_all()));
buf.write_str("def").unwrap();
assert_eq!("def", escape_ascii(buf.read_all()));
assert_eq!("", escape_ascii(buf.read_all()));
}
#[tokio::test]
async fn test_read_delimited_example() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
assert_eq!("", escape_ascii(buf.readable()));
let mut input = std::io::Cursor::new(b"aaa\nbbb\n\nccc\n");
assert_eq!(
"aaa",
escape_ascii(buf.read_delimited(&mut input, b"\n").await.unwrap())
);
assert_eq!(
"bbb",
escape_ascii(buf.read_delimited(&mut input, b"\n").await.unwrap())
);
assert_eq!(
"",
escape_ascii(buf.read_delimited(&mut input, b"\n").await.unwrap())
);
assert_eq!(
"ccc",
escape_ascii(buf.read_delimited(&mut input, b"\n").await.unwrap())
);
assert_eq!(
std::io::ErrorKind::NotFound,
buf.read_delimited(&mut input, b"\n")
.await
.unwrap_err()
.kind()
);
}
#[tokio::test]
async fn test_read_delimited_empty() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
assert_eq!(
std::io::ErrorKind::NotFound,
buf.read_delimited(&mut std::io::Cursor::new(""), b"b")
.await
.unwrap_err()
.kind()
);
}
#[tokio::test]
async fn test_read_delimited_not_found_eof() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
assert_eq!(
std::io::ErrorKind::NotFound,
buf.read_delimited(&mut std::io::Cursor::new("abc"), b"d")
.await
.unwrap_err()
.kind()
);
buf.read_all();
}
#[tokio::test]
async fn test_read_delimited_not_found_buffer_almost_full() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
assert_eq!(
std::io::ErrorKind::NotFound,
buf.read_delimited(&mut std::io::Cursor::new(&"b".repeat(15)), b"d")
.await
.unwrap_err()
.kind()
);
}
#[tokio::test]
async fn test_read_delimited_not_found_buffer_full() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.read_delimited(&mut std::io::Cursor::new(&"b".repeat(16)), b"d")
.await
.unwrap_err()
.kind()
);
}
#[tokio::test]
async fn test_read_delimited_found() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
assert_eq!(
"ab",
escape_ascii(
buf.read_delimited(&mut std::io::Cursor::new("abc"), b"c")
.await
.unwrap()
)
);
}
#[tokio::test]
async fn test_read_delimited_found_with_leftover() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
assert_eq!(
"ab",
escape_ascii(
buf.read_delimited(&mut std::io::Cursor::new("abcdef"), b"c")
.await
.unwrap()
)
);
assert_eq!("def", escape_ascii(buf.read_all()));
}
struct AsyncReadableThatPanics;
impl tokio::io::AsyncRead for AsyncReadableThatPanics {
fn poll_read(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
_buf: &mut tokio::io::ReadBuf<'_>,
) -> Poll<Result<(), std::io::Error>> {
panic!("AsyncReadableThatPanics::poll_read called");
}
}
#[tokio::test]
async fn test_read_delimited_already_in_buffer() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
buf.write_str("abc").unwrap();
let mut input = AsyncReadableThatPanics {};
assert_eq!(
"ab",
escape_ascii(buf.read_delimited(&mut input, b"c").await.unwrap())
);
buf.write_str("aaxbbx").unwrap();
assert_eq!(
"aa",
escape_ascii(buf.read_delimited(&mut input, b"x").await.unwrap())
);
assert_eq!(
"bb",
escape_ascii(buf.read_delimited(&mut input, b"x").await.unwrap())
);
}
#[test]
fn test_std_io_write() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
std::io::Write::write(&mut buf, b"abc").unwrap();
assert_eq!("abc", escape_ascii(buf.readable()));
std::io::Write::write(&mut buf, b"def").unwrap();
assert_eq!("abcdef", escape_ascii(buf.readable()));
buf.read_bytes(1);
std::io::Write::write(&mut buf, b"g").unwrap();
assert_eq!("bcdefg", escape_ascii(buf.readable()));
std::io::Write::write(&mut buf, "h".repeat(8).as_bytes()).unwrap();
std::io::Write::write(&mut buf, b"i").unwrap();
assert_eq!(
std::io::ErrorKind::InvalidData,
std::io::Write::write(&mut buf, b"def").unwrap_err().kind()
);
}
#[tokio::test]
async fn test_async_write() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
tokio::io::AsyncWriteExt::write_all(&mut buf, b"abc")
.await
.unwrap();
assert_eq!("abc", escape_ascii(buf.readable()));
tokio::io::AsyncWriteExt::write_all(&mut buf, b"def")
.await
.unwrap();
assert_eq!("abcdef", escape_ascii(buf.readable()));
buf.read_bytes(1);
tokio::io::AsyncWriteExt::write_all(&mut buf, b"g")
.await
.unwrap();
assert_eq!("bcdefg", escape_ascii(buf.readable()));
tokio::io::AsyncWriteExt::write_all(&mut buf, "h".repeat(8).as_bytes())
.await
.unwrap();
tokio::io::AsyncWriteExt::write_all(&mut buf, b"i")
.await
.unwrap();
assert_eq!(
std::io::ErrorKind::InvalidData,
tokio::io::AsyncWriteExt::write_all(&mut buf, b"def")
.await
.unwrap_err()
.kind()
);
}
#[test]
fn test_std_io_read() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
let mut data = ['.' as u8; 16];
assert_eq!(0, std::io::Read::read(&mut buf, &mut data).unwrap());
assert_eq!("..........", escape_ascii(&data[..10]));
buf.write_str("abc").unwrap();
assert_eq!(3, std::io::Read::read(&mut buf, &mut data).unwrap());
assert_eq!("abc.......", escape_ascii(&data[..10]));
assert_eq!(0, std::io::Read::read(&mut buf, &mut data).unwrap());
let many_bs = "b".repeat(16);
buf.write_str(&many_bs).unwrap();
assert_eq!(16, std::io::Read::read(&mut buf, &mut data).unwrap());
assert_eq!(many_bs, escape_ascii(&data[..]));
assert_eq!(0, std::io::Read::read(&mut buf, &mut data).unwrap());
}
#[tokio::test]
async fn test_async_read() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::new();
let mut data = ['.' as u8; 16];
assert_eq!(
0,
tokio::io::AsyncReadExt::read(&mut buf, &mut data)
.await
.unwrap()
);
assert_eq!("..........", escape_ascii(&data[..10]));
buf.write_str("abc").unwrap();
assert_eq!(
3,
tokio::io::AsyncReadExt::read(&mut buf, &mut data)
.await
.unwrap()
);
assert_eq!("abc.......", escape_ascii(&data[..10]));
assert_eq!(
0,
tokio::io::AsyncReadExt::read(&mut buf, &mut data)
.await
.unwrap()
);
let many_bs = "b".repeat(16);
buf.write_str(&many_bs).unwrap();
assert_eq!(
16,
tokio::io::AsyncReadExt::read(&mut buf, &mut data)
.await
.unwrap()
);
assert_eq!(many_bs, escape_ascii(&data[..]));
assert_eq!(
0,
tokio::io::AsyncReadExt::read(&mut buf, &mut data)
.await
.unwrap()
);
}
#[test]
fn test_default() {
let array_buf: FixedBuf<[u8; 16]> = FixedBuf::default();
assert_eq!("", escape_ascii(array_buf.readable()));
let box_buf: FixedBuf<Box<[u8; 16]>> = FixedBuf::default();
assert_eq!("", escape_ascii(box_buf.readable()));
}
#[test]
fn test_debug() {
let mut array_buf: FixedBuf<[u8; 8]> = FixedBuf::default();
let mut box_buf: FixedBuf<Box<[u8; 16]>> = FixedBuf::new();
let mut mem = [0u8; 15];
let mut slice_buf = FixedBuf::new_with_slice(&mut mem);
array_buf.write_str("abc").unwrap();
box_buf.write_str("abc").unwrap();
slice_buf.write_str("abc").unwrap();
array_buf.read_bytes(1);
box_buf.read_bytes(1);
slice_buf.read_bytes(1);
assert_eq!(
"FixedBuf{5 writable, 2 readable: \"bc\"}",
format!("{:?}", array_buf)
);
assert_eq!(
"FixedBuf{13 writable, 2 readable: \"bc\"}",
format!("{:?}", box_buf)
);
assert_eq!(
"FixedBuf{12 writable, 2 readable: \"bc\"}",
format!("{:?}", slice_buf)
);
}
}