Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
4 changes: 4 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
6 changes: 4 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
#![cfg_attr(not(doc), no_std)]
#![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
Loading