Crate buf_ref_reader

Source
Expand description

Faster, growable buffering reader for when there’s little to no need to modify data, nor to keep it alive past next read.

std::io::BufReader works by copying data from its internal buffer into user-provided Vec/String, or, in case of .lines(), by emitting new heap-allocated String for each iteration. While convenient and versatile, this is not the fastest approach.

Instead, BufRefReader references its internal buffer with each read, returning &[u8]. Lack of extra allocations yields better read performance in situations where most (if not all) of read data:

  • requires no modifications,
  • is never used outside of a loop body and does not need to be duplicated into the heap for future use.

While being more performant, this approach also severely limits applicability of this reader:

  • it does not (and cannot) implement BufRead and cannot be used as a direct replacement for BufReader;
  • returned values are only valid between calls to reading functions (i.e. they cannot outlive even a single loop cycle), and Rust’s borrow checker will prevent you from using stale references;
  • consequently, BufRefReader cannot be turned into an Iterator (here’s an easy way to think about it: what would Iterator::collect() return?);
  • returned references are immutable;
  • obviously, there’s also nothing that can return Strings or &strs for you.

§Choice a of buffer

Use MmapBuffer unless:

  • slice-deque is not available for your platform (e.g. no support for mmap),
  • you need very small buffers (smaller than 1 memory page),
  • you’re about to create a lot of buffers in a short period of time (new() is relatively expensive),
  • you’re expecting buffer to grow a lot (consider, if possible, preallocating larger buffers through BufRefReaderBuilder.capacity),
  • you have some very special concerns re: memory maps and malloc bypass (special allocators, possible kernel inefficiency due to large amount of mapped memory regions etc.).

§Examples

Read data word by word:

use buf_ref_reader::*;

fn read<B: Buffer>() -> Result<(), Error>
where
	Error: From<B::Error>,
	// add this if you plan to `unwrap()` errors returned by `read()` et al.
	//B::Error: std::fmt::Debug,
{
	// &[u8] implements Read, hence we use it as our data source for this example
	let data = b"lorem ipsum dolor sit amet";
	let mut r = BufRefReaderBuilder::new(&data[..])
		.capacity(4)
		.build::<B>()?;

	assert_eq!(r.read_until(b' ')?, Some(&b"lorem "[..]));
	assert_eq!(r.read_until(b' ')?, Some(&b"ipsum "[..]));
	assert_eq!(r.read_until(b' ')?, Some(&b"dolor "[..]));
	assert_eq!(r.read_until(b' ')?, Some(&b"sit "[..]));
	assert_eq!(r.read_until(b' ')?, Some(&b"amet"[..]));
	assert_eq!(r.read_until(b' ')?, None); // EOF
	assert_eq!(r.read_until(b' ')?, None);

	Ok(())
}

fn main() {
	read::<VecBuffer>().unwrap();
	read::<MmapBuffer>().unwrap();
}

Structs§

BufRefReader
Buffering reader.
BufRefReaderBuilder
Builder for BufRefReader.
MmapBuffer
Buffer that uses circular buffer implemented with mirrored memory maps
VecBuffer
Vec-backed buffer

Enums§

Error
Error type that reading functions might emit

Traits§

Buffer
This trait abstracts common operations with actual buffer from implementation details