mod cursor;
use binrw::io::{Cursor, Error, ErrorKind, Read, Result};
#[derive(Debug)]
struct MalfunctioningEddie<'data> {
error: Option<Error>,
data: Cursor<&'data [u8]>,
}
impl<'data> MalfunctioningEddie<'data> {
fn new(data: &'data [u8]) -> Self {
Self {
error: None,
data: Cursor::new(data),
}
}
fn trigger_fatal_error(&mut self) {
self.error = Some(Error::new(ErrorKind::BrokenPipe, ""));
}
fn trigger_non_fatal_error(&mut self) {
self.error = Some(Error::new(ErrorKind::Interrupted, ""));
}
}
impl Read for MalfunctioningEddie<'_> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if let Some(error) = self.error.take() {
Err(error)
} else {
self.data.read(buf)
}
}
}
#[test]
fn sanity_check() {
use core::any::TypeId;
assert!(TypeId::of::<Cursor<[u8; 0]>>() != TypeId::of::<std::io::Cursor<[u8; 0]>>());
assert!(TypeId::of::<Error>() != TypeId::of::<std::io::Error>());
assert!(TypeId::of::<ErrorKind>() != TypeId::of::<std::io::ErrorKind>());
assert!(TypeId::of::<dyn Read>() != TypeId::of::<dyn std::io::Read>());
assert!(TypeId::of::<Result<()>>() != TypeId::of::<std::io::Result<()>>());
}
#[test]
fn bytes() {
let mut cursor = MalfunctioningEddie::new(b"\0\x01\x02\x03\x04\x05");
{
let mut bytes = cursor.by_ref().bytes();
assert!(matches!(bytes.next(), Some(Ok(0))));
assert!(matches!(bytes.next(), Some(Ok(1))));
}
cursor.trigger_non_fatal_error();
{
let mut bytes = cursor.by_ref().bytes();
assert!(matches!(bytes.next(), Some(Ok(2))));
}
let mut raw_read_data = [0u8; 2];
assert_eq!(cursor.read(&mut raw_read_data).unwrap(), 2);
assert_eq!(raw_read_data, [3, 4]);
cursor.trigger_fatal_error();
let mut bytes = cursor.bytes();
assert_eq!(
bytes.next().unwrap().unwrap_err().kind(),
ErrorKind::BrokenPipe
);
}
#[test]
fn read_exact() {
let mut cursor = MalfunctioningEddie::new(b"\0\x01\x02\x03\x04\x05");
let mut raw_read_data = [0u8; 2];
cursor.read_exact(&mut raw_read_data).unwrap();
assert_eq!(raw_read_data, [0, 1]);
cursor.trigger_non_fatal_error();
cursor.read_exact(&mut raw_read_data).unwrap();
assert_eq!(raw_read_data, [2, 3]);
cursor.trigger_fatal_error();
assert_eq!(
cursor.read_exact(&mut raw_read_data).unwrap_err().kind(),
ErrorKind::BrokenPipe
);
cursor.by_ref().read_exact(&mut raw_read_data).unwrap();
assert_eq!(raw_read_data, [4, 5]);
assert_eq!(
cursor.read_exact(&mut raw_read_data).unwrap_err().kind(),
ErrorKind::UnexpectedEof
);
}
#[test]
fn interrupt_once() {
struct InterruptReader(bool);
impl Read for InterruptReader {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if self.0 {
self.0 = false;
Err(Error::from(ErrorKind::Interrupted))
} else {
buf.fill(0);
Ok(buf.len())
}
}
}
let mut x = InterruptReader(true);
let mut out = [1, 2, 3, 4];
x.read_exact(&mut out).unwrap();
assert_eq!(out, [0, 0, 0, 0]);
let mut x = InterruptReader(true).bytes();
assert_eq!(x.next().unwrap().unwrap(), 0);
assert_eq!(x.next().unwrap().unwrap(), 0);
assert_eq!(x.next().unwrap().unwrap(), 0);
assert_eq!(x.next().unwrap().unwrap(), 0);
}
#[test]
fn return_error() {
struct ReturnError(Option<Error>);
impl Read for ReturnError {
fn read(&mut self, _buf: &mut [u8]) -> Result<usize> {
Err(self.0.take().unwrap())
}
}
let mut x = ReturnError(Some(Error::from(ErrorKind::ConnectionRefused)));
let mut out = [0, 1, 2, 3];
assert_eq!(
x.read_exact(&mut out).unwrap_err().kind(),
ErrorKind::ConnectionRefused
);
let mut x = ReturnError(Some(Error::from(ErrorKind::ConnectionRefused))).bytes();
assert_eq!(
x.next().unwrap().unwrap_err().kind(),
ErrorKind::ConnectionRefused
);
}
#[test]
fn read_to_end() {
const IN: &[u8] = b"ABCD";
let mut x = Cursor::new(IN);
let mut out = Vec::new();
assert_eq!(x.read_to_end(&mut out).unwrap(), IN.len());
assert_eq!(out, IN);
struct InterruptReader(bool);
impl Read for InterruptReader {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if self.0 {
self.0 = false;
Err(Error::from(ErrorKind::Interrupted))
} else {
buf.fill(0);
Ok(buf.len())
}
}
}
const LIMIT: usize = 23;
let x = InterruptReader(true);
let mut out = Vec::new();
assert_eq!(x.take(LIMIT as _).read_to_end(&mut out).unwrap(), LIMIT);
assert_eq!(out.len(), 23);
struct ReturnError(Option<Error>);
impl Read for ReturnError {
fn read(&mut self, _buf: &mut [u8]) -> Result<usize> {
Err(self.0.take().unwrap())
}
}
let mut x = ReturnError(Some(Error::from(ErrorKind::ConnectionRefused)));
let mut out = Vec::new();
assert_eq!(
x.read_to_end(&mut out).unwrap_err().kind(),
ErrorKind::ConnectionRefused
);
}
#[test]
fn read_to_string() {
let mut s = String::from("hello");
let mut cursor = Cursor::new(b"world");
assert_eq!(cursor.read_to_string(&mut s).unwrap(), 5);
assert_eq!(s, "helloworld");
let mut cursor = Cursor::new(b"oops\x80");
cursor.read_to_string(&mut s).unwrap_err();
assert_eq!(s, "helloworld");
}
#[test]
fn take() {
const IN: &[u8] = b"ABCD";
const LIMIT: usize = 2;
let x = Cursor::new(IN);
let mut out = Vec::new();
assert_eq!(x.take(LIMIT as u64).read_to_end(&mut out).unwrap(), LIMIT);
assert_eq!(out, &IN[..LIMIT]);
struct ReturnError(Option<Error>);
impl Read for ReturnError {
fn read(&mut self, _buf: &mut [u8]) -> Result<usize> {
Err(self.0.take().unwrap())
}
}
let x = ReturnError(Some(Error::from(ErrorKind::ConnectionRefused)));
let mut out = Vec::new();
assert_eq!(
x.take(LIMIT as _).read_to_end(&mut out).unwrap_err().kind(),
ErrorKind::ConnectionRefused
);
let x = ReturnError(Some(Error::from(ErrorKind::ConnectionRefused)));
let mut out = Vec::new();
assert_eq!(x.take(0).read_to_end(&mut out).unwrap(), 0);
assert_eq!(out.len(), 0);
let x = ReturnError(Some(Error::from(ErrorKind::ConnectionRefused)));
assert_eq!(
x.take(0)
.into_inner()
.read_to_end(&mut out)
.unwrap_err()
.kind(),
ErrorKind::ConnectionRefused
);
}