Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/buffered/bufwriter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ impl<W: ?Sized + Write> BufWriter<W> {
self.buf.capacity()
}

pub(crate) fn buffer_mut(&mut self) -> &mut Buffer {
&mut self.buf
}

/// Send data in our local buffer into the inner writer, looping as
/// necessary until either it's all been sent or an error occurs.
///
Expand Down Expand Up @@ -195,6 +199,7 @@ impl<W: ?Sized + Write> BufWriter<W> {
return Err(Error::WriteZero);
}
Ok(n) => guard.consume(n),
#[cfg(feature = "continue-on-interrupt")]
Err(ref e) if e.canonicalize() == Error::Interrupted => {}
Err(e) => return Err(e),
}
Expand Down
8 changes: 5 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#![doc = include_str!("../README.md")]
#![cfg_attr(not(doc), no_std)]
#![feature(doc_cfg)]
#![cfg_attr(doc, feature(doc_cfg))]
#![feature(core_io_borrowed_buf)]
#![cfg_attr(not(borrowedbuf_init), feature(maybe_uninit_fill))]
#![feature(min_specialization)]
#![feature(maybe_uninit_fill)]
#![cfg_attr(not(maybe_uninit_slice), feature(maybe_uninit_slice))]
#![warn(missing_docs)]

Expand All @@ -18,9 +19,10 @@ mod buffered;
pub mod prelude;
mod read;
mod seek;
mod utils;
mod write;

pub use self::{buffered::*, read::*, seek::*, write::*};
pub use self::{buffered::*, read::*, seek::*, utils::*, write::*};

/// I/O poll results.
#[derive(Debug, Default, Clone, Copy)]
Expand Down
30 changes: 29 additions & 1 deletion src/read/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use alloc::{string::String, vec::Vec};
use core::io::BorrowedCursor;

use crate::{Error, Result};
use crate::{Chain, Error, Result, Take};

mod impls;

Expand Down Expand Up @@ -324,6 +324,34 @@ pub trait Read {
{
self
}

/// Creates an adapter which will chain this stream with another.
///
/// The returned `Read` instance will first read all bytes from this object
/// until EOF is encountered. Afterwards the output is equivalent to the
/// output of `next`.
fn chain<R: Read>(self, next: R) -> Chain<Self, R>
where
Self: Sized,
{
Chain::new(self, next)
}

/// Creates an adapter which will read at most `limit` bytes from it.
///
/// This function returns a new instance of `Read` which will read at most
/// `limit` bytes, after which it will always return EOF ([`Ok(0)`]). Any
/// read errors will not count towards the number of bytes read and future
/// calls to [`read()`] may succeed.
///
/// [`Ok(0)`]: Ok
/// [`read()`]: Read::read
fn take(self, limit: u64) -> Take<Self>
where
Self: Sized,
{
Take::new(self, limit)
}
}

/// Reads all bytes from a [reader][Read] into a new [`String`].
Expand Down
136 changes: 136 additions & 0 deletions src/utils/chain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::io::BorrowedCursor;

use crate::{BufRead, Read, Result};

/// Adapter to chain together two readers.
///
/// This struct is generally created by calling [`chain`] on a reader.
/// Please see the documentation of [`chain`] for more details.
///
/// See [`std::io::Chain`] for more details.
///
/// [`chain`]: Read::chain
#[derive(Debug)]
pub struct Chain<T, U> {
first: T,
second: U,
done_first: bool,
}

impl<T, U> Chain<T, U> {
pub(crate) fn new(first: T, second: U) -> Self {
Chain {
first,
second,
done_first: false,
}
}

/// Consumes the `Chain`, returning the wrapped readers.
pub fn into_inner(self) -> (T, U) {
(self.first, self.second)
}

/// Gets references to the underlying readers in this `Chain`.
///
/// Care should be taken to avoid modifying the internal I/O state of the
/// underlying readers as doing so may corrupt the internal state of this
/// `Chain`.
pub fn get_ref(&self) -> (&T, &U) {
(&self.first, &self.second)
}

/// Gets mutable references to the underlying readers in this `Chain`.
///
/// Care should be taken to avoid modifying the internal I/O state of the
/// underlying readers as doing so may corrupt the internal state of this
/// `Chain`.
pub fn get_mut(&mut self) -> (&mut T, &mut U) {
(&mut self.first, &mut self.second)
}
}

impl<T: Read, U: Read> Read for Chain<T, U> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if !self.done_first {
match self.first.read(buf)? {
0 if !buf.is_empty() => self.done_first = true,
n => return Ok(n),
}
}
self.second.read(buf)
}

fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> {
if buf.capacity() == 0 {
return Ok(());
}

if !self.done_first {
let old_len = buf.written();
self.first.read_buf(buf.reborrow())?;

if buf.written() != old_len {
return Ok(());
} else {
self.done_first = true;
}
}
self.second.read_buf(buf)
}

#[cfg(feature = "alloc")]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
let mut read = 0;
if !self.done_first {
read += self.first.read_to_end(buf)?;
self.done_first = true;
}
read += self.second.read_to_end(buf)?;
Ok(read)
}

// We don't override `read_to_string` here because an UTF-8 sequence could
// be split between the two parts of the chain
}

impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
fn fill_buf(&mut self) -> Result<&[u8]> {
if !self.done_first {
match self.first.fill_buf()? {
[] => self.done_first = true,
buf => return Ok(buf),
}
}
self.second.fill_buf()
}

fn consume(&mut self, amt: usize) {
if !self.done_first {
self.first.consume(amt)
} else {
self.second.consume(amt)
}
}

#[cfg(feature = "alloc")]
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
let mut read = 0;
if !self.done_first {
let n = self.first.read_until(byte, buf)?;
read += n;

match buf.last() {
Some(b) if *b == byte && n != 0 => return Ok(read),
_ => self.done_first = true,
}
}
read += self.second.read_until(byte, buf)?;
Ok(read)
}

// We don't override `read_line` here because an UTF-8 sequence could be
// split between the two parts of the chain
}
Loading