#![cfg_attr(not(doc), no_std)]
#![feature(doc_cfg)]
#![feature(core_io_borrowed_buf)]
#![cfg_attr(not(borrowedbuf_init), feature(maybe_uninit_fill))]
#[cfg(feature = "alloc")]
extern crate alloc;
use core::fmt;
mod buffered;
mod error;
mod impls;
pub mod prelude;
pub use self::buffered::BufReader;
pub use self::error::{Error, Result};
#[cfg(feature = "alloc")]
use alloc::{string::String, vec::Vec};
use axerrno::ax_err;
#[cfg(feature = "alloc")]
pub fn default_read_to_end<R: Read + ?Sized>(
r: &mut R,
buf: &mut Vec<u8>,
size_hint: Option<usize>,
) -> Result<usize> {
use core::io::BorrowedBuf;
const DEFAULT_BUF_SIZE: usize = 1024;
let start_len = buf.len();
let start_cap = buf.capacity();
let mut max_read_size = size_hint
.and_then(|s| {
s.checked_add(1024)?
.checked_next_multiple_of(DEFAULT_BUF_SIZE)
})
.unwrap_or(DEFAULT_BUF_SIZE);
const PROBE_SIZE: usize = 32;
fn small_probe_read<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
let mut probe = [0u8; PROBE_SIZE];
let n = r.read(&mut probe)?;
buf.extend_from_slice(&probe[..n]);
Ok(n)
}
if (size_hint.is_none() || size_hint == Some(0)) && buf.capacity() - buf.len() < PROBE_SIZE {
let read = small_probe_read(r, buf)?;
if read == 0 {
return Ok(0);
}
}
#[cfg(borrowedbuf_init)]
let mut initialized = 0; #[cfg(borrowedbuf_init)]
let mut consecutive_short_reads = 0;
loop {
if buf.len() == buf.capacity() && buf.capacity() == start_cap {
let read = small_probe_read(r, buf)?;
if read == 0 {
return Ok(buf.len() - start_len);
}
}
if buf.len() == buf.capacity() {
if let Err(e) = buf.try_reserve(PROBE_SIZE) {
return ax_err!(NoMemory, e);
}
}
let mut spare = buf.spare_capacity_mut();
let buf_len = spare.len().min(max_read_size);
spare = &mut spare[..buf_len];
let mut read_buf: BorrowedBuf<'_> = spare.into();
#[cfg(borrowedbuf_init)]
unsafe {
read_buf.set_init(initialized);
}
let mut cursor = read_buf.unfilled();
#[cfg(borrowedbuf_init)]
{
let n = r.read(cursor.ensure_init().init_mut())?;
cursor.advance(n);
}
#[cfg(not(borrowedbuf_init))]
{
let n = r.read(unsafe { cursor.as_mut().write_filled(0) })?;
assert!(n <= cursor.capacity());
unsafe {
cursor.advance(n);
}
}
#[cfg(borrowedbuf_init)]
let unfilled_but_initialized = cursor.init_mut().len();
let bytes_read = cursor.written();
#[cfg(borrowedbuf_init)]
let was_fully_initialized = read_buf.init_len() == buf_len;
unsafe {
let new_len = bytes_read + buf.len();
buf.set_len(new_len);
}
if bytes_read == 0 {
return Ok(buf.len() - start_len);
}
#[cfg(borrowedbuf_init)]
if bytes_read < buf_len {
consecutive_short_reads += 1;
} else {
consecutive_short_reads = 0;
}
#[cfg(borrowedbuf_init)]
{
initialized = unfilled_but_initialized;
}
if size_hint.is_none() {
#[cfg(borrowedbuf_init)]
if !was_fully_initialized && consecutive_short_reads > 1 {
max_read_size = usize::MAX;
}
if buf_len >= max_read_size && bytes_read == buf_len {
max_read_size = max_read_size.saturating_mul(2);
}
}
}
}
pub trait Read {
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
#[cfg(feature = "alloc")]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
default_read_to_end(self, buf, None)
}
#[cfg(feature = "alloc")]
fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
unsafe { append_to_string(buf, |b| self.read_to_end(b)) }
}
fn read_exact(&mut self, mut buf: &mut [u8]) -> Result {
while !buf.is_empty() {
match self.read(buf) {
Ok(0) => break,
Ok(n) => {
let tmp = buf;
buf = &mut tmp[n..];
}
Err(e) => return Err(e),
}
}
if !buf.is_empty() {
ax_err!(UnexpectedEof, "failed to fill whole buffer")
} else {
Ok(())
}
}
}
pub trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize>;
fn flush(&mut self) -> Result;
fn write_all(&mut self, mut buf: &[u8]) -> Result {
while !buf.is_empty() {
match self.write(buf) {
Ok(0) => return ax_err!(WriteZero, "failed to write whole buffer"),
Ok(n) => buf = &buf[n..],
Err(e) => return Err(e),
}
}
Ok(())
}
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> {
struct Adapter<'a, T: ?Sized + 'a> {
inner: &'a mut T,
error: Result<()>,
}
impl<T: Write + ?Sized> fmt::Write for Adapter<'_, T> {
fn write_str(&mut self, s: &str) -> fmt::Result {
match self.inner.write_all(s.as_bytes()) {
Ok(()) => Ok(()),
Err(e) => {
self.error = Err(e);
Err(fmt::Error)
}
}
}
}
let mut output = Adapter {
inner: self,
error: Ok(()),
};
match fmt::write(&mut output, fmt) {
Ok(()) => Ok(()),
Err(..) => {
if output.error.is_err() {
output.error
} else {
ax_err!(InvalidData, "formatter error")
}
}
}
}
}
pub trait Seek {
fn seek(&mut self, pos: SeekFrom) -> Result<u64>;
fn rewind(&mut self) -> Result<()> {
self.seek(SeekFrom::Start(0))?;
Ok(())
}
fn stream_position(&mut self) -> Result<u64> {
self.seek(SeekFrom::Current(0))
}
}
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
pub enum SeekFrom {
Start(u64),
End(i64),
Current(i64),
}
pub trait BufRead: Read {
fn fill_buf(&mut self) -> Result<&[u8]>;
fn consume(&mut self, amt: usize);
fn has_data_left(&mut self) -> Result<bool> {
self.fill_buf().map(|b| !b.is_empty())
}
#[cfg(feature = "alloc")]
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
let mut read = 0;
loop {
let (done, used) = {
let available = match self.fill_buf() {
Ok(n) => n,
Err(Error::WouldBlock) => continue,
Err(e) => return Err(e),
};
match available.iter().position(|&b| b == byte) {
Some(i) => {
buf.extend_from_slice(&available[..=i]);
(true, i + 1)
}
None => {
buf.extend_from_slice(available);
(false, available.len())
}
}
};
self.consume(used);
read += used;
if done || used == 0 {
return Ok(read);
}
}
}
#[cfg(feature = "alloc")]
fn read_line(&mut self, buf: &mut String) -> Result<usize> {
unsafe { append_to_string(buf, |b| self.read_until(b'\n', b)) }
}
}
#[cfg(feature = "alloc")]
unsafe fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
where
F: FnOnce(&mut Vec<u8>) -> Result<usize>,
{
let old_len = buf.len();
let buf = unsafe { buf.as_mut_vec() };
let ret = f(buf)?;
if core::str::from_utf8(&buf[old_len..]).is_err() {
ax_err!(InvalidData, "stream did not contain valid UTF-8")
} else {
Ok(ret)
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct PollState {
pub readable: bool,
pub writable: bool,
}