#![forbid(unsafe_code)]
mod escape_ascii;
pub use escape_ascii::escape_ascii;
mod deframe_crlf;
pub use deframe_crlf::deframe_crlf;
mod deframe_line;
pub use deframe_line::deframe_line;
mod read_write_chain;
pub use read_write_chain::*;
mod read_write_take;
pub use read_write_take::*;
#[cfg(test)]
mod test_utils;
#[cfg(test)]
pub use test_utils::*;
#[derive(Clone, PartialEq, Debug)]
pub struct NotEnoughSpaceError {}
#[derive(Debug, PartialEq, Clone)]
pub struct MalformedInputError(String);
impl MalformedInputError {
pub fn new(msg: String) -> Self {
Self(msg)
}
}
#[derive(Default, Copy, Clone, Eq, Hash, PartialEq)]
pub struct FixedBuf<T> {
mem: T,
read_index: usize,
write_index: usize,
}
impl<T> std::panic::UnwindSafe for FixedBuf<T> {}
impl<T> FixedBuf<T> {
pub const fn new(mem: T) -> Self {
Self {
mem,
write_index: 0,
read_index: 0,
}
}
pub fn into_inner(self) -> T {
self.mem
}
pub fn len(&self) -> usize {
self.write_index - self.read_index
}
pub fn is_empty(&self) -> bool {
self.write_index == self.read_index
}
pub fn clear(&mut self) {
self.read_index = 0;
self.write_index = 0;
}
}
impl<T: AsRef<[u8]>> FixedBuf<T> {
pub fn filled(mem: T) -> Self {
Self {
write_index: mem.as_ref().len(),
read_index: 0,
mem,
}
}
pub fn capacity(&self) -> usize {
self.mem.as_ref().len()
}
pub fn escape_ascii(&self) -> String {
escape_ascii(self.readable())
}
pub fn mem(&self) -> &[u8] {
self.mem.as_ref()
}
pub fn readable(&self) -> &[u8] {
&self.mem.as_ref()[self.read_index..self.write_index]
}
pub fn read_byte(&mut self) -> u8 {
self.read_bytes(1)[0]
}
pub fn try_read_byte(&mut self) -> Option<u8> {
if self.is_empty() {
None
} else {
Some(self.read_byte())
}
}
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.as_ref()[old_read_index..new_read_index]
}
pub fn try_read_bytes(&mut self, num_bytes: usize) -> Option<&[u8]> {
if self.len() < num_bytes {
None
} else {
Some(self.read_bytes(num_bytes))
}
}
pub fn read_all(&mut self) -> &[u8] {
self.read_bytes(self.len())
}
pub fn read_and_copy_bytes(&mut self, dest: &mut [u8]) -> usize {
let readable = self.readable();
let len = core::cmp::min(dest.len(), readable.len());
if len == 0 {
return 0;
}
let src = &readable[..len];
let copy_dest = &mut dest[..len];
copy_dest.copy_from_slice(src);
self.read_bytes(len);
len
}
pub fn try_read_exact(&mut self, dest: &mut [u8]) -> Option<()> {
if self.len() < dest.len() {
return None;
}
self.read_and_copy_bytes(dest);
Some(())
}
pub fn try_parse<R, F>(&mut self, f: F) -> Option<R>
where
F: FnOnce(&mut FixedBuf<&[u8]>) -> Option<R>,
{
let mut ro_buf = FixedBuf::filled(self.readable());
let result = f(&mut ro_buf);
if result.is_some() {
let num_bytes_read = ro_buf.capacity() - ro_buf.len();
self.read_bytes(num_bytes_read);
}
result
}
}
impl<T: AsMut<[u8]>> FixedBuf<T> {
pub fn copy_once_from<R: std::io::Read>(
&mut self,
reader: &mut R,
) -> Result<usize, std::io::Error> {
let mut writable = self.writable().ok_or_else(|| {
std::io::Error::new(std::io::ErrorKind::InvalidData, "no empty space in buffer")
})?;
let num_read = reader.read(&mut writable)?;
self.wrote(num_read);
Ok(num_read)
}
pub fn write_str(&mut self, s: &str) -> Result<(), NotEnoughSpaceError> {
self.write_bytes(s.as_bytes()).map(|_| ())
}
pub fn write_bytes(&mut self, data: &[u8]) -> core::result::Result<usize, NotEnoughSpaceError> {
let writable = self.writable().ok_or_else(|| NotEnoughSpaceError {})?;
if writable.len() < data.len() {
return Err(NotEnoughSpaceError {});
}
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.as_mut().len() {
return None;
}
Some(&mut self.mem.as_mut()[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.as_mut().len() {
panic!("write would overflow");
}
self.write_index = new_write_index;
}
pub fn shift(&mut self) {
if self.read_index == 0 {
return;
}
self.mem
.as_mut()
.copy_within(self.read_index..self.write_index, 0);
self.write_index -= self.read_index;
self.read_index = 0;
}
}
impl<T: AsRef<[u8]> + AsMut<[u8]>> FixedBuf<T> {
pub fn deframe<F>(
&mut self,
deframer_fn: F,
) -> Result<Option<core::ops::Range<usize>>, std::io::Error>
where
F: Fn(&[u8]) -> Result<Option<(core::ops::Range<usize>, usize)>, MalformedInputError>,
{
if self.is_empty() {
return Ok(None);
}
match deframer_fn(self.readable()) {
Err(e) => Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("{:?}", e),
)),
Ok(Some((data_range, block_len))) => {
let mem_start = self.read_index + data_range.start;
let mem_end = self.read_index + data_range.end;
self.read_bytes(block_len);
Ok(Some(mem_start..mem_end))
}
Ok(None) => Ok(None),
}
}
pub fn read_frame<R, F>(
&mut self,
reader: &mut R,
deframer_fn: F,
) -> Result<Option<&[u8]>, std::io::Error>
where
R: std::io::Read,
F: Fn(&[u8]) -> Result<Option<(core::ops::Range<usize>, usize)>, MalformedInputError>,
{
loop {
if !self.is_empty() {
if let Some(frame_range) = self.deframe(&deframer_fn)? {
return Ok(Some(&self.mem()[frame_range]));
}
}
self.shift();
let writable = self.writable().ok_or_else(|| {
std::io::Error::new(std::io::ErrorKind::InvalidData, "end of buffer full")
})?;
let num_read = reader.read(writable)?;
if num_read == 0 {
if self.is_empty() {
return Ok(None);
}
return Err(std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
"eof after reading part of a frame",
));
}
self.wrote(num_read);
}
}
}
impl<T: AsMut<[u8]>> std::io::Write for FixedBuf<T> {
fn write(&mut self, data: &[u8]) -> std::io::Result<usize> {
self.write_bytes(data).map_err(|_| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
"not enough space in buffer",
)
})
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl<T: AsRef<[u8]>> std::io::Read for FixedBuf<T> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
Ok(self.read_and_copy_bytes(buf))
}
}
impl<T: AsRef<[u8]>> core::fmt::Debug for FixedBuf<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::result::Result<(), core::fmt::Error> {
write!(
f,
"FixedBuf{{{} writable, {} readable: \"{}\"}}",
self.capacity() - self.write_index,
self.len(),
self.escape_ascii()
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use once_cell::sync::Lazy;
use std::sync::Mutex;
static STATIC_FIXED_BUF: Lazy<Mutex<FixedBuf<[u8; 128 * 1024]>>> =
Lazy::new(|| Mutex::new(FixedBuf::new([0; 128 * 1024])));
fn deframe_line_reject_xs(
data: &[u8],
) -> Result<Option<(core::ops::Range<usize>, usize)>, MalformedInputError> {
if data.contains(&b'x') || data.contains(&b'X') {
return Err(MalformedInputError::new("err1".to_string()));
}
deframe_line(data)
}
#[test]
fn test_static_fixed_buf() {
let mut buf = STATIC_FIXED_BUF.lock().unwrap();
assert_eq!(0, buf.len());
buf.write_str("abc").unwrap();
assert_eq!("abc", buf.escape_ascii());
}
#[test]
fn test_new() {
let _: FixedBuf<[u8; 1]> = FixedBuf::new([0; 1]);
let _: FixedBuf<[u8; 42]> = FixedBuf::new([0; 42]);
let _: FixedBuf<[u8; 256 * 1024]> = FixedBuf::new([0; 256 * 1024]);
}
#[test]
fn test_new_box_slice() {
let _: FixedBuf<Box<[u8]>> = FixedBuf::new(Box::new([0; 1]));
let _: FixedBuf<Box<[u8]>> = FixedBuf::new(Box::new([0; 42]));
let _: FixedBuf<Box<[u8]>> = FixedBuf::new(Box::new([0; 512 * 1024]));
}
#[test]
fn test_array_constructors() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
buf.write_str("abc").unwrap();
assert_eq!("abc", buf.escape_ascii());
let mem: [u8; 16] = buf.into_inner();
buf = FixedBuf::new(mem);
assert_eq!("", buf.escape_ascii());
buf.wrote(3);
assert_eq!("abc", escape_ascii(buf.read_all()));
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_box_array_constructors() {
let mut buf: FixedBuf<Box<[u8]>> = FixedBuf::new(Box::new([0u8; 16]) as Box<[u8]>);
buf.write_str("abc").unwrap();
assert_eq!("abc", buf.escape_ascii());
let mem = buf.into_inner();
buf = FixedBuf::new(mem);
assert_eq!("", buf.escape_ascii());
buf.wrote(3);
assert_eq!("abc", escape_ascii(buf.read_all()));
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_slice_constructor() {
let mut mem = [0u8; 15];
let mut buf = FixedBuf::new(&mut mem);
buf.write_str("abc").unwrap();
assert_eq!("abc", buf.escape_ascii());
buf = FixedBuf::new(&mut mem);
assert_eq!("", buf.escape_ascii());
buf.wrote(3);
assert_eq!("abc", escape_ascii(buf.read_all()));
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_filled_const() {
let mut buf = FixedBuf::filled(b"abc");
assert_eq!("abc", escape_ascii(buf.read_all()));
}
#[test]
fn test_filled_array() {
let mut buf = FixedBuf::filled([7u8; 10]);
assert_eq!(&[7], buf.read_bytes(1));
buf.write_bytes(&[42u8]).unwrap_err();
buf.shift();
buf.write_bytes(&[42u8]).unwrap();
}
#[test]
fn test_filled_box_array() {
let mut buf: FixedBuf<Box<[u8]>> = FixedBuf::filled(Box::new([7u8; 10]));
assert_eq!(&[7], buf.read_bytes(1));
buf.write_bytes(&[42u8]).unwrap_err();
buf.shift();
buf.write_bytes(&[42u8]).unwrap();
}
#[test]
fn empty() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
assert_eq!("", buf.escape_ascii());
assert_eq!("", escape_ascii(buf.read_all()));
buf.shift();
assert_eq!("", buf.escape_ascii());
assert_eq!("", escape_ascii(buf.read_all()));
}
#[test]
fn test_len() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
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_is_empty() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
assert!(buf.is_empty());
buf.write_str("abc").unwrap();
assert!(!buf.is_empty());
buf.read_all();
assert!(buf.is_empty());
}
#[test]
fn test_clear() {
let mut buf = FixedBuf::filled(b"abc");
assert_eq!(3, buf.len());
buf.clear();
assert!(buf.is_empty());
}
#[test]
fn test_write_str() {
let mut buf: FixedBuf<[u8; 4]> = FixedBuf::default();
buf.write_str("a").unwrap();
buf.write_str("bc").unwrap();
assert_eq!("abc", buf.escape_ascii());
assert_eq!(Err(NotEnoughSpaceError {}), buf.write_str("de"));
buf.write_str("d").unwrap();
assert_eq!("abcd", buf.escape_ascii());
assert_eq!(Err(NotEnoughSpaceError {}), buf.write_str("e"));
}
#[test]
fn test_write_bytes() {
let mut buf: FixedBuf<[u8; 4]> = FixedBuf::default();
assert_eq!(Ok(1usize), buf.write_bytes(b"a"));
assert_eq!(Ok(2), buf.write_bytes(b"bc"));
assert_eq!("abc", buf.escape_ascii());
assert_eq!(Err(NotEnoughSpaceError {}), buf.write_bytes(b"de"));
assert_eq!(Ok(1), buf.write_bytes(b"d"));
assert_eq!("abcd", buf.escape_ascii());
assert_eq!(Err(NotEnoughSpaceError {}), buf.write_bytes(b"e"));
}
#[test]
fn test_writable_and_wrote() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
assert_eq!(16, buf.writable().unwrap().len());
buf.writable().unwrap()[0] = 'a' as u8;
buf.wrote(1);
assert_eq!("a", buf.escape_ascii());
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, buf.escape_ascii());
assert_eq!(None, buf.writable());
}
#[test]
#[should_panic]
fn test_wrote_too_much() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
buf.wrote(17);
}
#[test]
fn test_shift_empty() {
let mut buf: FixedBuf<[u8; 4]> = FixedBuf::default();
buf.shift();
buf.write_str("abcd").unwrap();
assert_eq!("abcd", buf.escape_ascii());
}
#[test]
fn test_shift_half_filled() {
let mut buf: FixedBuf<[u8; 6]> = FixedBuf::default();
buf.write_str("abcd").unwrap();
buf.shift();
buf.read_bytes(2);
buf.write_str("ef").unwrap();
assert_eq!(NotEnoughSpaceError {}, buf.write_str("gh").unwrap_err());
buf.shift();
buf.write_str("gh").unwrap();
assert_eq!("cdefgh", buf.escape_ascii());
}
#[test]
fn test_shift_full() {
let mut buf: FixedBuf<[u8; 4]> = FixedBuf::default();
buf.write_str("abcd").unwrap();
buf.shift();
buf.read_bytes(2);
assert_eq!(NotEnoughSpaceError {}, buf.write_str("e").unwrap_err());
buf.shift();
buf.write_str("e").unwrap();
buf.write_str("f").unwrap();
assert_eq!(NotEnoughSpaceError {}, buf.write_str("g").unwrap_err());
assert_eq!("cdef", buf.escape_ascii());
}
#[test]
fn test_shift_read_all() {
let mut buf: FixedBuf<[u8; 4]> = FixedBuf::default();
buf.write_str("abcd").unwrap();
buf.read_bytes(4);
buf.shift();
buf.write_str("efgh").unwrap();
assert_eq!("efgh", buf.escape_ascii());
}
#[test]
fn test_deframe() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
assert_eq!(None, buf.deframe(deframe_line_reject_xs).unwrap());
buf.write_str("abc").unwrap();
assert_eq!(None, buf.deframe(deframe_line_reject_xs).unwrap());
assert_eq!("abc", buf.escape_ascii());
buf.write_str("\n").unwrap();
assert_eq!(Some(0..3), buf.deframe(deframe_line_reject_xs).unwrap());
assert_eq!("", buf.escape_ascii());
buf.write_str("x").unwrap();
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.deframe(deframe_line_reject_xs).unwrap_err().kind()
);
}
#[test]
fn test_read_frame_empty_to_eof() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
let mut reader = std::io::Cursor::new(b"");
assert_eq!(
None,
buf.read_frame(&mut reader, deframe_line_reject_xs).unwrap()
);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_frame_empty_to_incomplete() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
let mut reader = std::io::Cursor::new(b"abc");
assert_eq!(
std::io::ErrorKind::UnexpectedEof,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("abc", buf.escape_ascii());
}
#[test]
fn test_read_frame_empty_to_complete() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
let mut reader = std::io::Cursor::new(b"abc\n");
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_frame_empty_to_complete_with_leftover() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
let mut reader = std::io::Cursor::new(b"abc\nde");
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("de", buf.escape_ascii());
}
#[test]
fn test_read_frame_empty_to_invalid() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
let mut reader = std::io::Cursor::new(b"x");
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("x", buf.escape_ascii());
}
#[test]
fn test_read_frame_incomplete_to_eof() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
buf.write_str("a").unwrap();
let mut reader = std::io::Cursor::new(b"");
assert_eq!(
std::io::ErrorKind::UnexpectedEof,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("a", buf.escape_ascii());
}
#[test]
fn test_read_frame_incomplete_to_incomplete() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
buf.write_str("a").unwrap();
let mut reader = std::io::Cursor::new(b"bc");
assert_eq!(
std::io::ErrorKind::UnexpectedEof,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("abc", buf.escape_ascii());
}
#[test]
fn test_read_frame_incomplete_to_complete() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
buf.write_str("a").unwrap();
let mut reader = std::io::Cursor::new(b"bc\n");
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_frame_incomplete_to_complete_with_leftover() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
buf.write_str("a").unwrap();
let mut reader = std::io::Cursor::new(b"bc\nde");
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("de", buf.escape_ascii());
}
#[test]
fn test_read_frame_complete_doesnt_read() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
buf.write_str("abc\n").unwrap();
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut FakeReadWriter::empty(), deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_frame_complete_leaves_leftovers() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
buf.write_str("abc\nde").unwrap();
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut FakeReadWriter::empty(), deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("de", buf.escape_ascii());
}
#[test]
fn test_read_frame_invalid_doesnt_read() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
buf.write_str("x").unwrap();
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.read_frame(&mut FakeReadWriter::empty(), deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("x", buf.escape_ascii());
}
#[test]
fn test_read_frame_buffer_full() {
let mut buf: FixedBuf<[u8; 8]> = FixedBuf::default();
buf.write_str("abcdefgh").unwrap();
let mut reader = std::io::Cursor::new(b"bc\nde");
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("abcdefgh", buf.escape_ascii());
}
#[test]
fn test_readable() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
assert_eq!("", escape_ascii(buf.readable()));
buf.write_str("abc").unwrap();
assert_eq!("abc", escape_ascii(buf.readable()));
buf.read_bytes(2);
assert_eq!("c", escape_ascii(buf.readable()));
buf.read_bytes(1);
assert_eq!("", escape_ascii(buf.readable()));
buf.write_str("d").unwrap();
assert_eq!("d", escape_ascii(buf.readable()));
buf.shift();
assert_eq!("d", escape_ascii(buf.readable()));
}
#[test]
fn test_read_byte() {
let mut buf = FixedBuf::filled(b"abc");
assert_eq!(b'a', buf.read_byte());
assert_eq!("bc", buf.escape_ascii());
assert_eq!(b'b', buf.read_byte());
assert_eq!("c", buf.escape_ascii());
assert_eq!(b'c', buf.read_byte());
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_byte_mut() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
assert_eq!("", buf.escape_ascii());
buf.write_str("ab").unwrap();
assert_eq!(b'a', buf.read_byte());
assert_eq!("b", buf.escape_ascii());
buf.write_str("c").unwrap();
assert_eq!("bc", buf.escape_ascii());
assert_eq!(b'b', buf.read_byte());
assert_eq!("c", buf.escape_ascii());
assert_eq!(b'c', buf.read_byte());
assert_eq!("", buf.escape_ascii());
buf.write_str("d").unwrap();
assert_eq!("d", buf.escape_ascii());
assert_eq!(b'd', buf.read_byte());
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_bytes() {
let mut buf = FixedBuf::filled("abc");
assert_eq!("a", escape_ascii(buf.read_bytes(1)));
assert_eq!("bc", buf.escape_ascii());
assert_eq!("bc", escape_ascii(buf.read_bytes(2)));
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_bytes_mut() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
buf.write_str("abc").unwrap();
assert_eq!("a", escape_ascii(buf.read_bytes(1)));
assert_eq!("bc", buf.escape_ascii());
assert_eq!("bc", escape_ascii(buf.read_bytes(2)));
assert_eq!("", buf.escape_ascii());
buf.write_str("d").unwrap();
buf.shift();
buf.write_str("e").unwrap();
assert_eq!("d", escape_ascii(buf.read_bytes(1)));
assert_eq!("e", buf.escape_ascii());
}
#[test]
#[should_panic]
fn test_read_bytes_underflow() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
buf.write_str("a").unwrap();
buf.read_bytes(2);
}
#[test]
fn test_try_read_bytes() {
let mut buf = FixedBuf::filled(b"abc");
assert_eq!(Some("a".as_bytes()), buf.try_read_bytes(1));
assert_eq!("bc", buf.escape_ascii());
assert_eq!(None, buf.try_read_bytes(3));
assert_eq!("bc", buf.escape_ascii());
assert_eq!(Some("bc".as_bytes()), buf.try_read_bytes(2));
assert_eq!("", buf.escape_ascii());
assert_eq!(None, buf.try_read_bytes(1));
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_try_read_bytes_mut() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
buf.write_str("abc").unwrap();
assert_eq!(Some("a".as_bytes()), buf.try_read_bytes(1));
assert_eq!("bc", buf.escape_ascii());
assert_eq!(None, buf.try_read_bytes(3));
assert_eq!("bc", buf.escape_ascii());
assert_eq!(Some("bc".as_bytes()), buf.try_read_bytes(2));
assert_eq!("", buf.escape_ascii());
assert_eq!(None, buf.try_read_bytes(1));
assert_eq!("", buf.escape_ascii());
buf.write_str("d").unwrap();
buf.shift();
buf.write_str("e").unwrap();
assert_eq!(Some("d".as_bytes()), buf.try_read_bytes(1));
assert_eq!("e", buf.escape_ascii());
}
#[test]
fn test_read_all() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
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()));
}
#[test]
fn test_read_and_copy_bytes() {
let mut buf = FixedBuf::filled("abc");
let mut one = [0_u8; 1];
assert_eq!(1, buf.read_and_copy_bytes(&mut one));
assert_eq!(b"a", &one);
assert_eq!("bc", buf.escape_ascii());
let mut four = [0_u8; 4];
assert_eq!(2, buf.read_and_copy_bytes(&mut four));
assert_eq!(&[b'b', b'c', 0, 0], &four);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_and_copy_bytes_mut() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
buf.write_str("abc").unwrap();
let mut one = [0_u8; 1];
assert_eq!(1, buf.read_and_copy_bytes(&mut one));
assert_eq!(b"a", &one);
assert_eq!("bc", buf.escape_ascii());
let mut four = [0_u8; 4];
assert_eq!(2, buf.read_and_copy_bytes(&mut four));
assert_eq!(&[b'b', b'c', 0, 0], &four);
assert_eq!("", buf.escape_ascii());
buf.write_str("d").unwrap();
buf.shift();
buf.write_str("e").unwrap();
assert_eq!(1, buf.read_and_copy_bytes(&mut one));
assert_eq!(b"d", &one);
assert_eq!("e", buf.escape_ascii());
}
#[test]
fn test_try_read_exact() {
let mut buf = FixedBuf::filled("abc");
let mut one = [0_u8; 1];
buf.try_read_exact(&mut one).unwrap();
assert_eq!(b"a", &one);
assert_eq!("bc", buf.escape_ascii());
let mut three = [0_u8; 3];
assert_eq!(None, buf.try_read_exact(&mut three));
assert_eq!(&[0, 0, 0], &three);
let mut two = [0_u8; 2];
buf.try_read_exact(&mut two).unwrap();
assert_eq!(b"bc", &two);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_try_read_exact_mut() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
buf.write_str("abc").unwrap();
let mut one = [0_u8; 1];
buf.try_read_exact(&mut one).unwrap();
assert_eq!(b"a", &one);
assert_eq!("bc", buf.escape_ascii());
let mut three = [0_u8; 3];
assert_eq!(None, buf.try_read_exact(&mut three));
assert_eq!(&[0, 0, 0], &three);
assert_eq!("bc", buf.escape_ascii());
buf.write_str("d").unwrap();
buf.shift();
buf.write_str("e").unwrap();
buf.try_read_exact(&mut three).unwrap();
assert_eq!(b"bcd", &three);
assert_eq!("e", buf.escape_ascii());
}
#[test]
fn test_try_parse() {
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
enum CountError {
BadValue,
TooShort,
TooLong,
}
impl core::fmt::Display for CountError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
core::fmt::Debug::fmt(self, f)
}
}
impl std::error::Error for CountError {}
fn count_as(buf: &mut FixedBuf<&[u8]>) -> Option<Result<usize, CountError>> {
let mut count: usize = 0;
loop {
match buf.try_read_byte()? {
b'a' => {
count += 1;
if count > 3 {
return Some(Err(CountError::TooLong));
}
}
b'b' if count < 1 => return Some(Err(CountError::TooShort)),
b'b' => return Some(Ok(count)),
_ => return Some(Err(CountError::BadValue)),
}
}
}
assert_eq!(None, FixedBuf::filled(b"").try_parse(count_as));
assert_eq!(None, FixedBuf::filled(b"a").try_parse(count_as));
assert_eq!(None, FixedBuf::filled(b"aa").try_parse(count_as));
assert_eq!(None, FixedBuf::filled(b"aaa").try_parse(count_as));
assert_eq!(
Some(Err(CountError::TooLong)),
FixedBuf::filled(b"aaaa").try_parse(count_as)
);
assert_eq!(
Some(Err(CountError::TooShort)),
FixedBuf::filled(b"b").try_parse(count_as)
);
assert_eq!(Some(Ok(1)), FixedBuf::filled(b"ab").try_parse(count_as));
assert_eq!(Some(Ok(2)), FixedBuf::filled(b"aab").try_parse(count_as));
assert_eq!(Some(Ok(3)), FixedBuf::filled(b"aaab").try_parse(count_as));
assert_eq!(
Some(Err(CountError::TooLong)),
FixedBuf::filled(b"aaaab").try_parse(count_as)
);
assert_eq!(
Some(Err(CountError::BadValue)),
FixedBuf::filled(b"ac").try_parse(count_as)
);
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
assert_eq!(None, buf.try_parse(count_as));
buf.write_str("a").unwrap();
assert_eq!(None, buf.try_parse(count_as));
assert_eq!("a", buf.escape_ascii());
buf.write_str("baaba").unwrap();
assert_eq!(Some(Ok(1)), buf.try_parse(count_as));
assert_eq!("aaba", buf.escape_ascii());
assert_eq!(Some(Ok(2)), buf.try_parse(count_as));
assert_eq!("a", buf.escape_ascii());
assert_eq!(None, buf.try_parse(count_as));
buf.write_str("cbab").unwrap();
assert_eq!(Some(Err(CountError::BadValue)), buf.try_parse(count_as));
assert_eq!("bab", buf.escape_ascii());
buf.clear();
buf.write_str("b").unwrap();
assert_eq!(Some(Err(CountError::TooShort)), buf.try_parse(count_as));
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_copy_once_from() {
let mut buf: FixedBuf<[u8; 4]> = FixedBuf::default();
buf.write_str("a").unwrap();
assert_eq!(
2,
buf.copy_once_from(&mut std::io::Cursor::new(b"12"))
.unwrap()
);
assert_eq!("a12", escape_ascii(buf.read_all()));
assert_eq!(
3,
buf.copy_once_from(&mut std::io::Cursor::new(b"123"))
.unwrap()
);
assert_eq!("123", escape_ascii(buf.read_all()));
assert_eq!(
4,
buf.copy_once_from(&mut std::io::Cursor::new(b"1234"))
.unwrap()
);
assert_eq!("1234", escape_ascii(buf.read_all()));
assert_eq!(
4,
buf.copy_once_from(&mut std::io::Cursor::new(b"12345"))
.unwrap()
);
assert_eq!("1234", escape_ascii(buf.read_all()));
buf.write_str("abcd").unwrap();
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.copy_once_from(&mut std::io::Cursor::new(b"1"))
.unwrap_err()
.kind()
);
assert_eq!("abcd", escape_ascii(buf.read_all()));
assert_eq!(
2,
buf.copy_once_from(&mut FakeReadWriter::new(vec![Ok(2)]))
.unwrap()
);
assert_eq!("ab", escape_ascii(buf.read_all()));
}
#[test]
fn test_capacity() {
assert_eq!(0, FixedBuf::new([0u8; 0]).capacity());
assert_eq!(16, FixedBuf::new([0u8; 16]).capacity());
let buf: FixedBuf<Box<[u8]>> = FixedBuf::new(Box::new([0u8; 16]));
assert_eq!(16, buf.capacity());
let mut mem = [0u8; 16];
assert_eq!(16, FixedBuf::new(&mut mem).capacity());
assert_eq!(16, FixedBuf::filled([0u8; 16]).capacity());
}
#[test]
fn test_escape_ascii() {
assert_eq!("", FixedBuf::filled(b"").escape_ascii());
assert_eq!("abc", FixedBuf::filled(b"abc").escape_ascii());
assert_eq!("\\r\\n", FixedBuf::filled(b"\r\n").escape_ascii());
assert_eq!(
"\\xe2\\x82\\xac",
FixedBuf::filled("€".as_bytes()).escape_ascii()
);
assert_eq!("\\x01", FixedBuf::filled(b"\x01").escape_ascii());
let buf = FixedBuf::filled(b"abc");
assert_eq!("abc", buf.escape_ascii());
assert_eq!(b"abc", buf.readable());
}
#[test]
fn test_std_io_write() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
std::io::Write::write(&mut buf, b"abc").unwrap();
assert_eq!("abc", buf.escape_ascii());
std::io::Write::write(&mut buf, b"def").unwrap();
assert_eq!("abcdef", buf.escape_ascii());
buf.read_bytes(1);
std::io::Write::write(&mut buf, b"g").unwrap();
assert_eq!("bcdefg", buf.escape_ascii());
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()
);
}
#[test]
fn test_std_io_read() {
let mut buf: FixedBuf<[u8; 16]> = FixedBuf::default();
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());
}
#[test]
fn test_default() {
let _: FixedBuf<[u8; 8]> = FixedBuf::default();
let _: FixedBuf<[u8; 16]> = FixedBuf::default();
let mut array_buf: FixedBuf<[u8; 32]> = FixedBuf::default();
array_buf.write_str("abc").unwrap();
assert_eq!("abc", array_buf.escape_ascii());
let mut box_buf: FixedBuf<Box<[u8]>> = FixedBuf::default();
assert_eq!("", box_buf.escape_ascii());
assert!(box_buf.writable().is_none());
}
#[test]
fn test_debug() {
let mut array_buf: FixedBuf<[u8; 8]> = FixedBuf::default();
let mut box_buf: FixedBuf<Box<[u8]>> = FixedBuf::new(Box::new([0; 16]));
let mut mem = [0u8; 15];
let mut slice_buf = FixedBuf::new(&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)
);
}
}