#![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::{
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>;
const READ_CHUNK: usize = 1024;
#[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 {
if want_peek < buffer_len {
buf.copy_from_slice(&peek_buf[..want_peek]);
this.buffer.consume(..want_peek);
return Ok(want_peek);
} else if want_peek == buffer_len {
buf.copy_from_slice(peek_buf);
this.buffer.clear();
return Ok(want_peek);
} else {
buf[..buffer_len].copy_from_slice(peek_buf);
buf = &mut buf[buffer_len..];
let result = this.reader.read(buf);
this.buffer.clear();
return match result {
Ok(bytes) => Ok(bytes + buffer_len),
Err(_) => Ok(buffer_len),
};
}
}
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 {
if want_peek < buffer_len {
buf.copy_from_slice(&self.buffer.as_slice()[..want_peek]);
return Ok(want_peek);
} else if want_peek == buffer_len {
buf.copy_from_slice(self.buffer.as_slice());
return Ok(want_peek);
}
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),
}
};
return 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)
}
};
}
if want_peek == 0 {
return Ok(0);
}
let this = self;
let old_len = this.buffer.len();
this.buffer.resize(old_len + want_peek)?;
loop {
match this.reader.read(&mut this.buffer.as_mut_slice()[old_len..]) {
Ok(n) => {
this.buffer.truncate(old_len + n);
buf[..n].copy_from_slice(&this.buffer.as_slice()[old_len..old_len + n]);
return Ok(n);
}
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
Err(e) => {
this.buffer.truncate(old_len);
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;
buf.extend_from_slice(this.buffer.as_slice());
loop {
let old_len = this.buffer.len();
let growth = grow_peek_buffer(&mut this.buffer)?;
match this
.reader
.read(&mut this.buffer.as_mut_slice()[old_len..old_len + growth])
{
Ok(0) => {
this.buffer.truncate(old_len);
return Ok(this.buffer.len());
}
Ok(n) => {
this.buffer.truncate(old_len + n);
buf.extend_from_slice(&this.buffer.as_slice()[old_len..old_len + n]);
}
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {
this.buffer.truncate(old_len);
continue;
}
Err(e) => {
this.buffer.truncate(old_len);
return Err(e);
}
}
}
}
pub fn peek_to_string(&mut self, buf: &mut String) -> Result<usize> {
if let Err(e) = core::str::from_utf8(self.buffer.as_slice()) {
if e.error_len().is_some() {
return Err(invalid_utf8_io_error(e));
}
}
let loop_result: Result<()> = loop {
let old_len = self.buffer.len();
let growth = match grow_peek_buffer(&mut self.buffer) {
Ok(g) => g,
Err(e) => break Err(e),
};
match self
.reader
.read(&mut self.buffer.as_mut_slice()[old_len..old_len + growth])
{
Ok(0) => {
self.buffer.truncate(old_len);
break Ok(());
}
Ok(n) => {
self.buffer.truncate(old_len + n);
}
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {
self.buffer.truncate(old_len);
continue;
}
Err(e) => {
self.buffer.truncate(old_len);
break Err(e);
}
}
};
match (loop_result, core::str::from_utf8(self.buffer.as_slice())) {
(Ok(()), Ok(s)) => {
buf.push_str(s);
Ok(self.buffer.len())
}
(Ok(()), Err(e)) => Err(invalid_utf8_io_error(e)),
(Err(io), Ok(s)) => {
buf.push_str(s);
Err(io)
}
(Err(io), Err(utf8_err)) => {
let vut = utf8_err.valid_up_to();
if vut != 0 {
let s = core::str::from_utf8(&self.buffer.as_slice()[..vut])
.expect("valid_up_to() must point to a valid UTF-8 prefix");
buf.push_str(s);
}
Err(io)
}
}
}
pub fn peek_exact(&mut self, buf: &mut [u8]) -> Result<()> {
let this = self;
let total = buf.len();
let peek_buf_len = this.buffer.len();
if total <= peek_buf_len {
buf.copy_from_slice(&this.buffer.as_slice()[..total]);
return Ok(());
}
buf[..peek_buf_len].copy_from_slice(this.buffer.as_slice());
let mut filled = peek_buf_len;
while filled < total {
let old_len = this.buffer.len();
let want = total - filled;
this.buffer.resize(old_len + want)?;
let n = loop {
match this.reader.read(&mut this.buffer.as_mut_slice()[old_len..]) {
Ok(n) => break n,
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
Err(e) => {
this.buffer.truncate(old_len);
return Err(e);
}
}
};
this.buffer.truncate(old_len + n);
if n == 0 {
return Err(std::io::ErrorKind::UnexpectedEof.into());
}
buf[filled..filled + n].copy_from_slice(&this.buffer.as_slice()[old_len..old_len + n]);
filled += n;
}
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_attr(not(tarpaulin), inline)]
pub(crate) fn grow_peek_buffer<B: Buffer>(buffer: &mut B) -> std::io::Result<usize> {
let old_len = buffer.len();
let mut growth = READ_CHUNK;
loop {
match buffer.resize(old_len + growth) {
Ok(()) => return Ok(growth),
Err(_) if growth > 1 => growth /= 2,
Err(e) => return Err(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]);
}
}