#![doc = include_str!("../README.md")]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, allow(unused_attributes))]
#![deny(missing_docs)]
use buffer::Buffer;
use std::{
cmp,
io::{IoSliceMut, Read, Result, Write},
mem,
};
#[doc(hidden)]
#[cfg(feature = "smallvec")]
pub type DefaultBuffer = smallvec::SmallVec<[u8; 64]>;
#[doc(hidden)]
#[cfg(not(feature = "smallvec"))]
pub type DefaultBuffer = Vec<u8>;
#[cfg(any(feature = "tokio", feature = "future"))]
#[macro_export]
macro_rules! ready {
($e:expr $(,)?) => {
match $e {
::std::task::Poll::Ready(t) => t,
::std::task::Poll::Pending => return ::std::task::Poll::Pending,
}
};
}
#[cfg(feature = "future")]
#[cfg_attr(docsrs, doc(cfg(feature = "future")))]
pub mod future;
#[cfg(feature = "tokio")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
pub mod tokio;
pub mod buffer;
pub struct Peekable<R, B = DefaultBuffer> {
reader: R,
buffer: B,
buf_cap: Option<usize>,
}
impl<R, B> Read for Peekable<R, B>
where
B: buffer::Buffer,
R: Read,
{
fn read(&mut self, mut buf: &mut [u8]) -> Result<usize> {
let this = self;
let want_peek = buf.len();
let peek_buf = this.buffer.as_mut_slice();
let buffer_len = peek_buf.len();
if buffer_len > 0 {
return match want_peek.cmp(&buffer_len) {
cmp::Ordering::Less => {
buf.copy_from_slice(&peek_buf[..want_peek]);
this.buffer.consume(..want_peek);
return Ok(want_peek);
}
cmp::Ordering::Equal => {
buf.copy_from_slice(peek_buf);
this.buffer.clear();
return Ok(want_peek);
}
cmp::Ordering::Greater => {
buf[..buffer_len].copy_from_slice(peek_buf);
buf = &mut buf[buffer_len..];
match this.reader.read(buf) {
Ok(bytes) => {
this.buffer.clear();
Ok(bytes + buffer_len)
}
Err(e) => Err(e),
}
}
};
}
this.reader.read(buf)
}
}
impl<W, B> Write for Peekable<W, B>
where
W: Write,
B: Buffer,
{
#[cfg_attr(not(tarpaulin), inline(always))]
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.reader.write(buf)
}
#[cfg_attr(not(tarpaulin), inline(always))]
fn flush(&mut self) -> Result<()> {
self.reader.flush()
}
}
impl<R> From<R> for Peekable<R> {
#[cfg_attr(not(tarpaulin), inline(always))]
fn from(reader: R) -> Self {
Peekable::new(reader)
}
}
impl<R> From<(usize, R)> for Peekable<R> {
#[cfg_attr(not(tarpaulin), inline(always))]
fn from((cap, reader): (usize, R)) -> Self {
Peekable::with_capacity(reader, cap)
}
}
impl<R> Peekable<R> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn new(reader: R) -> Self {
Self::construct(reader, DefaultBuffer::new(), None)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn with_capacity(reader: R, capacity: usize) -> Self {
Self::construct(
reader,
DefaultBuffer::with_capacity(capacity),
Some(capacity),
)
}
}
impl<R, B> Peekable<R, B> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn with_buffer(reader: R) -> Self
where
B: Buffer,
{
Self::construct(reader, B::new(), None)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn with_capacity_and_buffer(reader: R, capacity: usize) -> Self
where
B: Buffer,
{
Self::construct(reader, B::with_capacity(capacity), Some(capacity))
}
#[cfg_attr(not(tarpaulin), inline(always))]
fn construct(reader: R, buffer: B, capacity: Option<usize>) -> Self
where
B: Buffer,
{
Self {
reader,
buffer,
buf_cap: capacity,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn consume(&mut self) -> B
where
B: Buffer,
{
let buf = match self.buf_cap {
Some(capacity) => B::with_capacity(capacity),
None => B::new(),
};
mem::replace(&mut self.buffer, buf)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn consume_in_place(&mut self)
where
B: Buffer,
{
self.buffer.clear();
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn get_mut(&mut self) -> (&[u8], &mut R)
where
B: AsRef<[u8]>,
{
(self.buffer.as_ref(), &mut self.reader)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn get_ref(&self) -> (&[u8], &R)
where
B: AsRef<[u8]>,
{
(self.buffer.as_ref(), &self.reader)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_components(self) -> (B, R) {
(self.buffer, self.reader)
}
}
impl<R, B> Peekable<R, B>
where
B: Buffer,
R: Read,
{
pub fn peek(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let want_peek = buf.len();
let buffer_len = self.buffer.len();
if buffer_len > 0 {
return match want_peek.cmp(&buffer_len) {
cmp::Ordering::Less => {
buf.copy_from_slice(&self.buffer.as_slice()[..want_peek]);
Ok(want_peek)
}
cmp::Ordering::Equal => {
buf.copy_from_slice(self.buffer.as_slice());
Ok(want_peek)
}
cmp::Ordering::Greater => {
self.buffer.resize(want_peek)?;
let result = loop {
match self
.reader
.read(&mut self.buffer.as_mut_slice()[buffer_len..])
{
Ok(n) => break Ok(n),
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
Err(e) => break Err(e),
}
};
match result {
Ok(n) => {
self.buffer.truncate(n + buffer_len);
buf[..buffer_len + n].copy_from_slice(self.buffer.as_slice());
Ok(buffer_len + n)
}
Err(e) => {
self.buffer.truncate(buffer_len);
Err(e)
}
}
}
};
}
let this = self;
loop {
match this.reader.read(buf) {
Ok(bytes) => {
this.buffer.extend_from_slice(&buf[..bytes])?;
return Ok(bytes);
}
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
}
}
}
pub fn peek_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> {
for b in bufs {
if !b.is_empty() {
return self.peek(b);
}
}
self.peek(&mut [])
}
pub fn peek_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
let this = &mut *self;
let inbuf = this.buffer.len();
let original_buf = buf.len();
buf.extend_from_slice(this.buffer.as_slice());
let fut = this.reader.read_to_end(buf);
match fut {
Ok(read) => {
this
.buffer
.extend_from_slice(&buf[original_buf + inbuf..])?;
Ok(read + inbuf)
}
Err(e) => Err(e),
}
}
pub fn peek_to_string(&mut self, buf: &mut String) -> Result<usize> {
let s = match core::str::from_utf8(self.buffer.as_slice()) {
Ok(s) => s,
Err(e) => return Err(invalid_utf8_io_error(e)),
};
buf.push_str(s);
let inbuf = self.buffer.len();
let fut = self.reader.read_to_string(buf);
match fut {
Ok(read) => {
self.buffer.extend_from_slice(&buf.as_bytes()[inbuf..])?;
Ok(read + inbuf)
}
Err(e) => Err(e),
}
}
pub fn peek_exact(&mut self, mut buf: &mut [u8]) -> Result<()> {
let this = self;
let buf_len = buf.len();
let peek_buf_len = this.buffer.len();
if buf_len <= peek_buf_len {
buf.copy_from_slice(&this.buffer.as_slice()[..buf_len]);
return Ok(());
}
buf[..peek_buf_len].copy_from_slice(this.buffer.as_slice());
{
let (_read, rest) = mem::take(&mut buf).split_at_mut(peek_buf_len);
buf = rest;
}
let mut readed = peek_buf_len;
while !buf.is_empty() {
let n = loop {
match this.reader.read(buf) {
Ok(n) => break n,
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
}
};
{
let (read, rest) = mem::take(&mut buf).split_at_mut(n);
this.buffer.extend_from_slice(read)?;
readed += n;
buf = rest;
}
if n == 0 && readed != buf_len {
return Err(std::io::ErrorKind::UnexpectedEof.into());
}
}
Ok(())
}
pub fn fill_peek_buf(&mut self) -> Result<usize> {
let cap = self.buffer.capacity();
let cur = self.buffer.len();
self.buffer.resize(cap)?;
let result = loop {
match self.reader.read(&mut self.buffer.as_mut_slice()[cur..]) {
Ok(n) => break Ok(n),
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
Err(e) => break Err(e),
}
};
match result {
Ok(peeked) => {
self.buffer.truncate(cur + peeked);
Ok(peeked)
}
Err(e) => {
self.buffer.truncate(cur);
Err(e)
}
}
}
}
pub trait PeekExt: Read {
fn peekable(self) -> Peekable<Self>
where
Self: Sized,
{
Peekable::from(self)
}
fn peekable_with_capacity(self, capacity: usize) -> Peekable<Self>
where
Self: Sized,
{
Peekable::from((capacity, self))
}
fn peekable_with_buffer<B>(self) -> Peekable<Self, B>
where
Self: Sized,
B: Buffer,
{
Peekable::with_buffer(self)
}
fn peekable_with_capacity_and_buffer<B>(self, capacity: usize) -> Peekable<Self, B>
where
Self: Sized,
B: Buffer,
{
Peekable::with_capacity_and_buffer(self, capacity)
}
}
impl<R: Read + ?Sized> PeekExt for R {}
#[cfg_attr(not(tarpaulin), inline(always))]
fn invalid_utf8_io_error(e: core::str::Utf8Error) -> std::io::Error {
std::io::Error::new(std::io::ErrorKind::InvalidData, e)
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test_peek_exact_peek_exact_read_exact() {
let mut peekable = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8, 9]).peekable();
let mut buf1 = [0; 2];
peekable.peek_exact(&mut buf1).unwrap();
assert_eq!(buf1, [1, 2]);
let mut buf2 = [0; 4];
peekable.peek_exact(&mut buf2).unwrap();
assert_eq!(buf2, [1, 2, 3, 4]);
let mut buf3 = [0; 4];
peekable.read_exact(&mut buf3).unwrap();
assert_eq!(buf3, [1, 2, 3, 4]);
}
#[test]
fn test_peek_exact_peek_exact_read_exact_2() {
let mut peekable = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8, 9]).peekable_with_buffer::<Vec<u8>>();
let mut buf1 = [0; 2];
peekable.peek_exact(&mut buf1).unwrap();
assert_eq!(buf1, [1, 2]);
let mut buf2 = [0; 4];
peekable.peek_exact(&mut buf2).unwrap();
assert_eq!(buf2, [1, 2, 3, 4]);
let mut buf3 = [0; 4];
peekable.read_exact(&mut buf3).unwrap();
assert_eq!(buf3, [1, 2, 3, 4]);
}
#[test]
fn test_peek_exact_peek_exact_read_exact_3() {
let mut peekable =
Cursor::new([1, 2, 3, 4, 5, 6, 7, 8, 9]).peekable_with_capacity_and_buffer::<Vec<u8>>(24);
let mut buf1 = [0; 2];
peekable.peek_exact(&mut buf1).unwrap();
assert_eq!(buf1, [1, 2]);
let mut buf2 = [0; 4];
peekable.peek_exact(&mut buf2).unwrap();
assert_eq!(buf2, [1, 2, 3, 4]);
let mut buf3 = [0; 4];
peekable.read_exact(&mut buf3).unwrap();
assert_eq!(buf3, [1, 2, 3, 4]);
}
}