Skip to content

Commit

Permalink
Rename Byte{Reader,Writer} to Deferred{Reader,Writer}
Browse files Browse the repository at this point in the history
  • Loading branch information
jix committed Dec 23, 2021
1 parent 6161c13 commit 7e758dd
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 74 deletions.
4 changes: 2 additions & 2 deletions flussab-cnf/examples/roundtrip_cnf.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::io::Write;

use flussab::ByteWriter;
use flussab::DeferredWriter;

use flussab_cnf::{cnf, ParseError};

Expand All @@ -15,7 +15,7 @@ fn main_err() -> Result<(), ParseError> {
let stdout = std::io::stdout();

let mut cnf_reader = cnf::Parser::<i32>::from_read(stdin.lock(), true)?;
let mut cnf_writer = ByteWriter::from_write(stdout.lock());
let mut cnf_writer = DeferredWriter::from_write(stdout.lock());

if let Some(header) = cnf_reader.header() {
cnf::write_header(&mut cnf_writer, header)?;
Expand Down
4 changes: 2 additions & 2 deletions flussab-cnf/examples/roundtrip_gcnf.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::io::Write;

use flussab::ByteWriter;
use flussab::DeferredWriter;

use flussab_cnf::{gcnf, ParseError};

Expand All @@ -15,7 +15,7 @@ fn main_err() -> Result<(), ParseError> {
let stdout = std::io::stdout();

let mut gcnf_reader = gcnf::Parser::<i32>::from_read(stdin.lock(), true)?;
let mut gcnf_writer = ByteWriter::from_write(stdout.lock());
let mut gcnf_writer = DeferredWriter::from_write(stdout.lock());

if let Some(header) = gcnf_reader.header() {
gcnf::write_header(&mut gcnf_writer, header)?;
Expand Down
4 changes: 2 additions & 2 deletions flussab-cnf/examples/roundtrip_wcnf.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::io::Write;

use flussab::ByteWriter;
use flussab::DeferredWriter;

use flussab_cnf::{wcnf, ParseError};

Expand All @@ -15,7 +15,7 @@ fn main_err() -> Result<(), ParseError> {
let stdout = std::io::stdout();

let mut wcnf_reader = wcnf::Parser::<i32>::from_read(stdin.lock(), true)?;
let mut wcnf_writer = ByteWriter::from_write(stdout.lock());
let mut wcnf_writer = DeferredWriter::from_write(stdout.lock());

if let Some(header) = wcnf_reader.header() {
wcnf::write_header(&mut wcnf_writer, header)?;
Expand Down
8 changes: 4 additions & 4 deletions flussab-cnf/src/cnf.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Parsing and writing of the DIMACS CNF file format.
use std::io::{self, BufReader, Read, Write};

use flussab::{text::LineReader, ByteReader};
use flussab::{text::LineReader, DeferredReader};

use crate::{error::ParseError, token, Dimacs};

Expand Down Expand Up @@ -46,7 +46,7 @@ where
strict: bool,
) -> Result<Self, ParseError> {
Self::new(
LineReader::new(ByteReader::from_buf_reader(buf_reader)),
LineReader::new(DeferredReader::from_buf_reader(buf_reader)),
strict,
)
}
Expand All @@ -60,7 +60,7 @@ where
/// When `strict` is false, the variable and clause count of the DIMACS CNF header are ignored
/// during parsing.
pub fn from_read(read: impl Read + 'a, strict: bool) -> Result<Self, ParseError> {
Self::new(LineReader::new(ByteReader::from_read(read)), strict)
Self::new(LineReader::new(DeferredReader::from_read(read)), strict)
}

/// Creates a parser reading from a boxed [`Read`] instance.
Expand All @@ -74,7 +74,7 @@ where
#[inline(never)]
pub fn from_boxed_dyn_read(read: Box<dyn Read + 'a>, strict: bool) -> Result<Self, ParseError> {
Self::new(
LineReader::new(ByteReader::from_boxed_dyn_read(read)),
LineReader::new(DeferredReader::from_boxed_dyn_read(read)),
strict,
)
}
Expand Down
8 changes: 4 additions & 4 deletions flussab-cnf/src/gcnf.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Parsing and writing of the GCNF file format for group oriented CNF formulas.
use std::io::{self, BufReader, Read, Write};

use flussab::{text::LineReader, ByteReader};
use flussab::{text::LineReader, DeferredReader};

use crate::{error::ParseError, token, Dimacs};

Expand Down Expand Up @@ -56,7 +56,7 @@ where
strict: bool,
) -> Result<Self, ParseError> {
Self::new(
LineReader::new(ByteReader::from_buf_reader(buf_reader)),
LineReader::new(DeferredReader::from_buf_reader(buf_reader)),
strict,
)
}
Expand All @@ -70,7 +70,7 @@ where
/// When `strict` is false, the variable and clause count of the header are ignored during
/// parsing.
pub fn from_read(read: impl Read + 'a, strict: bool) -> Result<Self, ParseError> {
Self::new(LineReader::new(ByteReader::from_read(read)), strict)
Self::new(LineReader::new(DeferredReader::from_read(read)), strict)
}

/// Creates a parser reading from a boxed [`Read`] instance.
Expand All @@ -84,7 +84,7 @@ where
#[inline(never)]
pub fn from_boxed_dyn_read(read: Box<dyn Read + 'a>, strict: bool) -> Result<Self, ParseError> {
Self::new(
LineReader::new(ByteReader::from_boxed_dyn_read(read)),
LineReader::new(DeferredReader::from_boxed_dyn_read(read)),
strict,
)
}
Expand Down
8 changes: 4 additions & 4 deletions flussab-cnf/src/wcnf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! Also known as WDIMACS.
use std::io::{self, BufReader, Read, Write};

use flussab::{text::LineReader, ByteReader};
use flussab::{text::LineReader, DeferredReader};

use crate::{error::ParseError, token, Dimacs};

Expand Down Expand Up @@ -54,7 +54,7 @@ where
strict: bool,
) -> Result<Self, ParseError> {
Self::new(
LineReader::new(ByteReader::from_buf_reader(buf_reader)),
LineReader::new(DeferredReader::from_buf_reader(buf_reader)),
strict,
)
}
Expand All @@ -68,7 +68,7 @@ where
/// When `strict` is false, the variable and clause count of the header are ignored during
/// parsing.
pub fn from_read(read: impl Read + 'a, strict: bool) -> Result<Self, ParseError> {
Self::new(LineReader::new(ByteReader::from_read(read)), strict)
Self::new(LineReader::new(DeferredReader::from_read(read)), strict)
}

/// Creates a parser reading from a boxed [`Read`] instance.
Expand All @@ -82,7 +82,7 @@ where
#[inline(never)]
pub fn from_boxed_dyn_read(read: Box<dyn Read + 'a>, strict: bool) -> Result<Self, ParseError> {
Self::new(
LineReader::new(ByteReader::from_boxed_dyn_read(read)),
LineReader::new(DeferredReader::from_boxed_dyn_read(read)),
strict,
)
}
Expand Down
18 changes: 9 additions & 9 deletions flussab/src/byte_reader.rs → flussab/src/deferred_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use std::io::{self, BufReader, Cursor, Read};
/// A buffered reader optimized for efficient parsing.
///
/// Like `std`'s [`BufReader`], this provides buffering to coalesce many small reads into fewer
/// larger reads of the underlying data source. The difference is that `ByteReader` is optimized for
/// efficient parsing. This includes asynchronous handling of IO errors, position tracking, and
/// larger reads of the underlying data source. The difference is that `DeferredReader` is optimized
/// for efficient parsing. This includes asynchronous handling of IO errors, position tracking, and
/// dynamic contiguous look-ahead.
pub struct ByteReader<'a> {
pub struct DeferredReader<'a> {
read: Box<dyn Read + 'a>,
buf: Vec<u8>,
// SAFETY `buf[pos_in_buf..pos_in_buf+valid_len]` must _always_ be valid
Expand All @@ -19,10 +19,10 @@ pub struct ByteReader<'a> {
chunk_size: usize,
}

impl<'a> ByteReader<'a> {
impl<'a> DeferredReader<'a> {
const DEFAULT_CHUNK_SIZE: usize = 16 << 10;

/// Creates a [`ByteReader`] for the data of a [`BufReader`].
/// Creates a [`DeferredReader`] for the data of a [`BufReader`].
pub fn from_buf_reader(buf_reader: BufReader<impl Read + 'a>) -> Self {
// Avoid double buffering without discarding any already buffered contents.
let buf_data = buf_reader.buffer().to_vec();
Expand All @@ -33,7 +33,7 @@ impl<'a> ByteReader<'a> {
}
}

/// Creates a [`ByteReader`] for the data of a [`Read`] instance.
/// Creates a [`DeferredReader`] for the data of a [`Read`] instance.
///
/// If the [`Read`] instance is a [`BufReader`], it is better to use
/// [`from_buf_reader`][Self::from_buf_reader] to avoid unnecessary double buffering of the
Expand All @@ -42,14 +42,14 @@ impl<'a> ByteReader<'a> {
Self::from_boxed_dyn_read(Box::new(read))
}

/// Creates a [`ByteReader`] for the data of a boxed [`Read`] instance.
/// Creates a [`DeferredReader`] for the data of a boxed [`Read`] instance.
///
/// If the [`Read`] instance is a [`BufReader`], it is better to use
/// [`from_buf_reader`][Self::from_buf_reader] to avoid unnecessary double buffering of the
/// data.
#[inline(never)]
pub fn from_boxed_dyn_read(read: Box<dyn Read + 'a>) -> Self {
ByteReader {
DeferredReader {
read,
buf: vec![],
pos_in_buf: 0,
Expand All @@ -66,7 +66,7 @@ impl<'a> ByteReader<'a> {
///
/// This sets the size of the [`read`][Read::read] requests made. Note that this is just an
/// upper bound. Depending on the [`Read`] implementation, smaller amounts may be read at once.
/// To enable interactive line based input, `ByteReader` on its own will not issue more read
/// To enable interactive line based input, `DeferredReader` on its own will not issue more read
/// requests than necessary.
pub fn set_chunk_size(&mut self, size: usize) {
self.chunk_size = size;
Expand Down
18 changes: 9 additions & 9 deletions flussab/src/byte_writer.rs → flussab/src/deferred_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,32 @@ use std::io::{self, Write};

/// A buffered writer with deferred error checking.
///
/// This can be used like [`std::io::BufWriter`], but like [`ByteReader`][crate::ByteReader] this
/// performs deferred error checking. This means that any call to [`write`][Write::write], will
/// This can be used like [`std::io::BufWriter`], but like [`DeferredReader`][crate::DeferredReader]
/// this performs deferred error checking. This means that any call to [`write`][Write::write], will
/// always succeed. IO errors that occur during writing will be reported during the next call to
/// [`flush`][Write::flush] or [`check_io_error`][Self::check_io_error]. Any data written after an
/// IO error occured, before it is eventually reported, will be discarded.
///
/// Deferring error checks like this can result in a significant speed up for some usage patterns.
pub struct ByteWriter<'a> {
pub struct DeferredWriter<'a> {
write: Box<dyn Write + 'a>,
buf: Vec<u8>,
io_error: Option<io::Error>,
panicked: bool,
}

impl<'a> ByteWriter<'a> {
impl<'a> DeferredWriter<'a> {
const DEFAULT_CHUNK_SIZE: usize = 16 << 10;

/// Creates a [`ByteWriter`] writing data to a [`Write`] instance.
/// Creates a [`DeferredWriter`] writing data to a [`Write`] instance.
pub fn from_write(write: impl Write + 'a) -> Self {
Self::from_boxed_dyn_write(Box::new(write))
}

/// Creates a [`ByteWriter`] writing data to a boxed [`Write`] instance.
/// Creates a [`DeferredWriter`] writing data to a boxed [`Write`] instance.
#[inline(never)]
pub fn from_boxed_dyn_write(write: Box<dyn Write + 'a>) -> Self {
ByteWriter {
DeferredWriter {
write,
buf: Vec::with_capacity(Self::DEFAULT_CHUNK_SIZE),
io_error: None,
Expand Down Expand Up @@ -119,7 +119,7 @@ impl<'a> ByteWriter<'a> {
}
}

impl<'a> Write for ByteWriter<'a> {
impl<'a> Write for DeferredWriter<'a> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.write_all_defer_err(buf);
Expand All @@ -139,7 +139,7 @@ impl<'a> Write for ByteWriter<'a> {
}
}

impl<'a> Drop for ByteWriter<'a> {
impl<'a> Drop for DeferredWriter<'a> {
fn drop(&mut self) {
if !self.panicked {
self.flush_defer_err();
Expand Down
28 changes: 14 additions & 14 deletions flussab/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//! hand-rolled parsers (e.g. using data parallelism to scan multiple input bytes at once).
//!
//! The efficiency is realized by a) using an input stream with a mutable cursor instead of
//! threading the current position through return values and b) (when using [`ByteReader`])
//! threading the current position through return values and b) (when using [`DeferredReader`])
//! deferring IO error checks. This together greatly simplifies the control and data flow of the
//! parsers, which makes it easier for the compiler to optimize the code and often results in
//! overall faster code.
Expand Down Expand Up @@ -42,8 +42,8 @@
//! back tracking. Avoiding backtracking completely also avoids many ways to accidentally making a
//! recursive-descent parser become very slow for some inputs. This does mean that some form of
//! look-ahead is required to parse most formats. This can be realized either by using the
//! provided [`ByteReader`] which has dynamic lookahead, and/or by using a tokenizer for formats
//! where no look-ahead is required after tokenization.
//! provided [`DeferredReader`] which has dynamic lookahead, and/or by using a tokenizer for
//! formats where no look-ahead is required after tokenization.
//!
//! (Note that Flussab doesn't stop you from handling backtracking yourself, it just does not
//! provide any help for that.)
Expand All @@ -55,8 +55,8 @@
//!
//! The provided infrastructure for combining parsers is entirely agnostic of how the input stream
//! is handled, as long as it itself keeps track of the input position. This crate provides
//! [`ByteReader`] as one choice, but a [`Peekable`][std::iter::Peekable] iterator of tokens would
//! work as well.
//! [`DeferredReader`] as one choice, but a [`Peekable`][std::iter::Peekable] iterator of tokens
//! would work as well.
//!
//! ## Using Flussab
//!
Expand All @@ -66,7 +66,7 @@
//! # use flussab::*;
//! # type Something = ();
//! # type ParseError = ();
//! fn something(input: &mut ByteReader) -> Parsed<Something, ParseError> {
//! fn something(input: &mut DeferredReader) -> Parsed<Something, ParseError> {
//! # let input_as_expected = false;
//! // Check whether `input` contains a _something_ at the current position
//! if !input_as_expected {
Expand All @@ -84,22 +84,22 @@
//! }
//! ```
//!
//! Here [`Parsed`] and [`ByteReader`] are provided by this crate and are good entry points for the
//! documentation. A `Parsed` value is just a wrapper for a [`Result`] which adds [`Fallthrough`] as
//! a third option besides `Ok` and `Err` that indicates that the input does not match and that the
//! parser did not consume any input.
//! Here [`Parsed`] and [`DeferredReader`] are provided by this crate and are good entry points for
//! the documentation. A `Parsed` value is just a wrapper for a [`Result`] which adds
//! [`Fallthrough`] as a third option besides `Ok` and `Err` that indicates that the input does not
//! match and that the parser did not consume any input.
//!
//! Instead of manually returning `Fallthrough` or `Res(Err(..))`, often the provided methods of
//! [`Parsed`] and [`Result`] are used to combine smaller parsers into larger ones.
#![warn(missing_docs)]
mod byte_reader;
mod byte_writer;
mod deferred_reader;
mod deferred_writer;
mod parser;
pub mod text;

pub use byte_reader::ByteReader;
pub use byte_writer::ByteWriter;
pub use deferred_reader::DeferredReader;
pub use deferred_writer::DeferredWriter;
pub use parser::{Parsed, Result, ResultExt};

pub use Parsed::*;
Loading

0 comments on commit 7e758dd

Please sign in to comment.