#![doc(html_favicon_url = "https://docs.sequoia-pgp.org/favicon.png")]
#![doc(html_logo_url = "https://docs.sequoia-pgp.org/logo.svg")]
#![warn(missing_docs)]
use std::io;
use std::io::{Error, ErrorKind};
use std::cmp;
use std::fmt;
use std::convert::TryInto;
#[macro_use]
mod macros;
mod generic;
mod memory;
mod limitor;
mod reserve;
mod dup;
mod eof;
mod adapter;
#[cfg(feature = "compression-deflate")]
mod decompress_deflate;
#[cfg(feature = "compression-bzip2")]
mod decompress_bzip2;
pub use self::generic::Generic;
pub use self::memory::Memory;
pub use self::limitor::Limitor;
pub use self::reserve::Reserve;
pub use self::dup::Dup;
pub use self::eof::EOF;
pub use self::adapter::Adapter;
#[cfg(feature = "compression-deflate")]
pub use self::decompress_deflate::Deflate;
#[cfg(feature = "compression-deflate")]
pub use self::decompress_deflate::Zlib;
#[cfg(feature = "compression-bzip2")]
pub use self::decompress_bzip2::Bzip;
mod file_error;
#[allow(dead_code)]
mod file_generic;
#[allow(dead_code)]
#[cfg(unix)]
mod file_unix;
#[cfg(not(unix))]
pub use self::file_generic::File;
#[cfg(unix)]
pub use self::file_unix::File;
lazy_static::lazy_static! {
static ref DEFAULT_BUF_SIZE_: usize = {
use std::env::var_os;
use std::str::FromStr;
let default = 32 * 1024;
if let Some(size) = var_os("SEQUOIA_BUFFERED_READER_BUFFER") {
size.to_str()
.and_then(|s| {
match FromStr::from_str(s) {
Ok(s) => Some(s),
Err(err) => {
eprintln!("Unable to parse the value of \
'SEQUOIA_BUFFERED_READER_BUFFER'; \
falling back to the default buffer \
size ({}): {}",
err, default);
None
}
}
})
.unwrap_or(default)
} else {
default
}
};
}
fn default_buf_size() -> usize {
*DEFAULT_BUF_SIZE_
}
fn vec_truncate(v: &mut Vec<u8>, len: usize) {
if cfg!(debug_assertions) {
if len < v.len() {
unsafe { v.set_len(len); }
}
} else {
v.truncate(len);
}
}
fn vec_resize(v: &mut Vec<u8>, new_size: usize) {
if v.len() < new_size {
v.resize(new_size, 0);
} else {
vec_truncate(v, new_size);
}
}
pub trait BufferedReader<C> : io::Read + fmt::Debug + fmt::Display + Send + Sync
where C: fmt::Debug + Send + Sync
{
fn buffer(&self) -> &[u8];
fn data(&mut self, amount: usize) -> Result<&[u8], io::Error>;
fn data_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
let result = self.data(amount);
if let Ok(buffer) = result {
if buffer.len() < amount {
return Err(Error::new(ErrorKind::UnexpectedEof,
"unexpected EOF"));
}
}
result
}
fn data_eof(&mut self) -> Result<&[u8], io::Error> {
let mut s = default_buf_size();
loop {
match self.data(s) {
Ok(buffer) => {
if buffer.len() < s {
s = buffer.len();
break;
} else {
s *= 2;
}
}
Err(err) =>
return Err(err),
}
}
let buffer = self.buffer();
assert_eq!(buffer.len(), s);
Ok(buffer)
}
fn consume(&mut self, amount: usize) -> &[u8];
fn data_consume(&mut self, amount: usize)
-> Result<&[u8], std::io::Error> {
let amount = cmp::min(amount, self.data(amount)?.len());
let buffer = self.consume(amount);
assert!(buffer.len() >= amount);
Ok(buffer)
}
fn data_consume_hard(&mut self, amount: usize)
-> Result<&[u8], io::Error>
{
let len = self.data_hard(amount)?.len();
assert!(len >= amount);
let buffer = self.consume(amount);
assert!(buffer.len() >= amount);
Ok(buffer)
}
fn eof(&mut self) -> bool {
self.data_hard(1).is_err()
}
fn consummated(&mut self) -> bool {
self.eof()
}
fn read_be_u16(&mut self) -> Result<u16, std::io::Error> {
let input = self.data_consume_hard(2)?;
Ok(u16::from_be_bytes(input[..2].try_into().unwrap()))
}
fn read_be_u32(&mut self) -> Result<u32, std::io::Error> {
let input = self.data_consume_hard(4)?;
Ok(u32::from_be_bytes(input[..4].try_into().unwrap()))
}
fn read_to(&mut self, terminal: u8) -> Result<&[u8], std::io::Error> {
let mut n = 128;
let len;
loop {
let data = self.data(n)?;
if let Some(newline)
= data.iter().position(|c| *c == terminal)
{
len = newline + 1;
break;
} else if data.len() < n {
len = data.len();
break;
} else {
n = cmp::max(2 * n, data.len() + 1024);
}
}
Ok(&self.buffer()[..len])
}
fn drop_until(&mut self, terminals: &[u8])
-> Result<usize, std::io::Error>
{
for t in terminals.windows(2) {
assert!(t[0] <= t[1]);
}
let mut total = 0;
let position = 'outer: loop {
let len = {
let buffer = if self.buffer().is_empty() {
self.data(default_buf_size())?
} else {
self.buffer()
};
if buffer.is_empty() {
break 'outer 0;
}
if let Some(position) = buffer.iter().position(
|c| terminals.binary_search(c).is_ok())
{
break 'outer position;
}
buffer.len()
};
self.consume(len);
total += len;
};
self.consume(position);
Ok(total + position)
}
fn drop_through(&mut self, terminals: &[u8], match_eof: bool)
-> Result<(Option<u8>, usize), std::io::Error>
{
let dropped = self.drop_until(terminals)?;
match self.data_consume(1) {
Ok([]) if match_eof => Ok((None, dropped)),
Ok([]) => Err(Error::new(ErrorKind::UnexpectedEof, "EOF")),
Ok(rest) => Ok((Some(rest[0]), dropped + 1)),
Err(err) => Err(err),
}
}
fn steal(&mut self, amount: usize) -> Result<Vec<u8>, std::io::Error> {
let mut data = self.data_consume_hard(amount)?;
assert!(data.len() >= amount);
if data.len() > amount {
data = &data[..amount];
}
Ok(data.to_vec())
}
fn steal_eof(&mut self) -> Result<Vec<u8>, std::io::Error> {
let len = self.data_eof()?.len();
let data = self.steal(len)?;
Ok(data)
}
fn drop_eof(&mut self) -> Result<bool, std::io::Error> {
let mut at_least_one_byte = false;
loop {
let n = self.data(default_buf_size())?.len();
at_least_one_byte |= n > 0;
self.consume(n);
if n < default_buf_size() {
break;
}
}
Ok(at_least_one_byte)
}
fn dump(&self, sink: &mut dyn std::io::Write) -> std::io::Result<()>
where Self: std::marker::Sized
{
let mut i = 1;
let mut reader: Option<&dyn BufferedReader<C>> = Some(self);
while let Some(r) = reader {
{
let cookie = r.cookie_ref();
writeln!(sink, " {}. {}, {:?}", i, r, cookie)?;
}
reader = r.get_ref();
i += 1;
}
Ok(())
}
#[allow(clippy::wrong_self_convention)]
fn as_boxed<'a>(self) -> Box<dyn BufferedReader<C> + 'a>
where Self: 'a + Sized
{
Box::new(self)
}
fn into_inner<'a>(self: Box<Self>) -> Option<Box<dyn BufferedReader<C> + 'a>>
where Self: 'a;
fn get_mut(&mut self) -> Option<&mut dyn BufferedReader<C>>;
fn get_ref(&self) -> Option<&dyn BufferedReader<C>>;
fn cookie_set(&mut self, cookie: C) -> C;
fn cookie_ref(&self) -> &C;
fn cookie_mut(&mut self) -> &mut C;
}
pub fn buffered_reader_generic_read_impl<T: BufferedReader<C>, C: fmt::Debug + Sync + Send>
(bio: &mut T, buf: &mut [u8]) -> Result<usize, io::Error> {
bio
.data_consume(buf.len())
.map(|inner| {
let amount = cmp::min(buf.len(), inner.len());
buf[0..amount].copy_from_slice(&inner[0..amount]);
amount
})
}
impl <'a, C: fmt::Debug + Sync + Send> BufferedReader<C> for Box<dyn BufferedReader<C> + 'a> {
fn buffer(&self) -> &[u8] {
return self.as_ref().buffer();
}
fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
return self.as_mut().data(amount);
}
fn data_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
return self.as_mut().data_hard(amount);
}
fn data_eof(&mut self) -> Result<&[u8], io::Error> {
return self.as_mut().data_eof();
}
fn consume(&mut self, amount: usize) -> &[u8] {
return self.as_mut().consume(amount);
}
fn data_consume(&mut self, amount: usize)
-> Result<&[u8], std::io::Error> {
return self.as_mut().data_consume(amount);
}
fn data_consume_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
return self.as_mut().data_consume_hard(amount);
}
fn consummated(&mut self) -> bool {
self.as_mut().consummated()
}
fn read_be_u16(&mut self) -> Result<u16, std::io::Error> {
return self.as_mut().read_be_u16();
}
fn read_be_u32(&mut self) -> Result<u32, std::io::Error> {
return self.as_mut().read_be_u32();
}
fn read_to(&mut self, terminal: u8) -> Result<&[u8], std::io::Error>
{
return self.as_mut().read_to(terminal);
}
fn steal(&mut self, amount: usize) -> Result<Vec<u8>, std::io::Error> {
return self.as_mut().steal(amount);
}
fn steal_eof(&mut self) -> Result<Vec<u8>, std::io::Error> {
return self.as_mut().steal_eof();
}
fn drop_eof(&mut self) -> Result<bool, std::io::Error> {
return self.as_mut().drop_eof();
}
fn get_mut(&mut self) -> Option<&mut dyn BufferedReader<C>> {
self.as_mut().get_mut()
}
fn get_ref(&self) -> Option<&dyn BufferedReader<C>> {
self.as_ref().get_ref()
}
fn as_boxed<'b>(self) -> Box<dyn BufferedReader<C> + 'b>
where Self: 'b
{
self
}
fn into_inner<'b>(self: Box<Self>) -> Option<Box<dyn BufferedReader<C> + 'b>>
where Self: 'b {
(*self).into_inner()
}
fn cookie_set(&mut self, cookie: C) -> C {
self.as_mut().cookie_set(cookie)
}
fn cookie_ref(&self) -> &C {
self.as_ref().cookie_ref()
}
fn cookie_mut(&mut self) -> &mut C {
self.as_mut().cookie_mut()
}
}
#[cfg(test)]
fn buffered_reader_test_data_check<'a, T: BufferedReader<C> + 'a, C: fmt::Debug + Sync + Send>(bio: &mut T) {
use std::str;
for i in 0 .. 10000 {
let consumed = {
let d = bio.data_hard(5);
if d.is_err() {
println!("Error for i == {}: {:?}", i, d);
}
let d = d.unwrap();
assert!(d.len() >= 5);
assert_eq!(format!("{:04}\n", i), str::from_utf8(&d[0..5]).unwrap());
5
};
bio.consume(consumed);
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn buffered_reader_eof_test() {
let data : &[u8] = include_bytes!("buffered-reader-test.txt");
{
let mut bio = Memory::new(data);
let amount = {
bio.data_eof().unwrap().len()
};
bio.consume(amount);
assert_eq!(bio.data(1).unwrap().len(), 0);
}
{
let bio = Memory::new(data);
let mut bio2 = Limitor::new(
bio, (data.len() / 2) as u64);
let amount = {
bio2.data_eof().unwrap().len()
};
assert_eq!(amount, data.len() / 2);
bio2.consume(amount);
assert_eq!(bio2.data(1).unwrap().len(), 0);
}
}
#[cfg(test)]
fn buffered_reader_read_test_aux<'a, T: BufferedReader<C> + 'a, C: fmt::Debug + Sync + Send>
(mut bio: T, data: &[u8]) {
let mut buffer = [0; 99];
assert!(buffer.len() < data.len());
let iters = (data.len() + buffer.len() - 1) / buffer.len();
for i in 1..iters + 2 {
let data_start = (i - 1) * buffer.len();
{
let result = bio.data(buffer.len());
let buffer = result.unwrap();
if !buffer.is_empty() {
assert_eq!(buffer,
&data[data_start..data_start + buffer.len()]);
}
}
let result = bio.read(&mut buffer[..]);
let got = result.unwrap();
if got > 0 {
assert_eq!(&buffer[0..got],
&data[data_start..data_start + got]);
}
if i > iters {
assert!(got == 0);
} else if i == iters {
assert!(0 < got);
assert!(got <= buffer.len());
} else {
assert_eq!(got, buffer.len());
}
}
}
#[test]
fn buffered_reader_read_test() {
let data : &[u8] = include_bytes!("buffered-reader-test.txt");
{
let bio = Memory::new(data);
buffered_reader_read_test_aux (bio, data);
}
{
use std::path::PathBuf;
use std::fs::File;
let path : PathBuf = [env!("CARGO_MANIFEST_DIR"),
"src",
"buffered-reader-test.txt"]
.iter().collect();
let mut f = File::open(&path).expect(&path.to_string_lossy());
let bio = Generic::new(&mut f, None);
buffered_reader_read_test_aux (bio, data);
}
}
#[test]
fn drop_until() {
let data : &[u8] = &b"abcd"[..];
let mut reader = Memory::new(data);
assert_eq!(reader.drop_until(b"ab").unwrap(), 0);
assert_eq!(reader.drop_until(b"bc").unwrap(), 1);
assert_eq!(reader.drop_until(b"ab").unwrap(), 0);
assert_eq!(reader.drop_until(b"de").unwrap(), 2);
assert_eq!(reader.drop_until(b"e").unwrap(), 1);
assert_eq!(reader.drop_until(b"e").unwrap(), 0);
}
#[test]
fn drop_through() {
let data : &[u8] = &b"abcd"[..];
let mut reader = Memory::new(data);
assert_eq!(reader.drop_through(b"ab", false).unwrap(),
(Some(b'a'), 1));
assert_eq!(reader.drop_through(b"ab", false).unwrap(),
(Some(b'b'), 1));
assert_eq!(reader.drop_through(b"def", false).unwrap(),
(Some(b'd'), 2));
assert!(reader.drop_through(b"def", false).is_err());
assert!(reader.drop_through(b"def", true).unwrap().0.is_none());
}
}