buffer-re(a)dux

Crates.io Crates.io Crates.io

Fork of the unmaintained buf_redux.

Drop-in replacements for buffered I/O types in std::io.

These replacements retain the method names/signatures and implemented traits of their stdlib counterparts, making replacement as simple as swapping the import of the type.

More Direct Control

All replacement types provide methods to: * Increase the capacity of the buffer * Get the number of available bytes as well as the total capacity of the buffer * Consume the wrapper without losing data

BufReader provides methods to: * Access the buffer through an &-reference without performing I/O * Force unconditional reads into the buffer * Get a Read adapter which empties the buffer and then pulls from the inner reader directly * Shuffle bytes down to the beginning of the buffer to make room for more reading * Get inner reader and trimmed buffer with the remaining data

BufWriter and LineWriter provide methods to: * Flush the buffer and unwrap the inner writer unconditionally.

More Sensible and Customizable Buffering Behavior

Tune the behavior of the buffer to your specific use-case using the types in the policy module:

Usage

Documentation

Cargo.toml: toml [dependencies] buffer-redux = "0.2" And then simply swap the import of the types you want to replace:

BufReader:

- use std::io::BufReader; + use buffer_redux::BufReader;

BufWriter:

- use std::io::BufWriter; + use buffer_redux::BufWriter;

LineWriter:

- use std::io::LineWriter; + use buffer_redux::LineWriter;

Using MinBuffered

The new policy::MinBuffered reader-policy can be used to ensure that BufReader always has at least a certain number of bytes in its buffer. This can be useful for parsing applications that require a certain amount of lookahead.

```rust use bufferredux::BufReader; use bufferredux::policy::MinBuffered; use std::io::{BufRead, Cursor};

let data = (1 .. 16).collect::>();

// normally you should use BufReader::new() or give a capacity of several KiB or more let mut reader = BufReader::withcapacity(8, Cursor::new(data)) // always at least 4 bytes in the buffer (or until the source is empty) .setpolicy(MinBuffered(4)); // always at least 4 bytes in the buffer

// first buffer fill, same as std::io::BufReader asserteq!(reader.fillbuf().unwrap(), &[1, 2, 3, 4, 5, 6, 7, 8]); reader.consume(3);

// enough data in the buffer, another read isn't done yet asserteq!(reader.fillbuf().unwrap(), &[4, 5, 6, 7, 8]); reader.consume(4);

// std::io::BufReader would return &[8] asserteq!(reader.fillbuf().unwrap(), &[8, 9, 10, 11, 12, 13, 14, 15]); reader.consume(5);

// no data left in the reader asserteq!(reader.fillbuf().unwrap(), &[13, 14, 15]); ```

Note: Making Room / Ringbuffers / slice-deque Feature

With policies like MinBuffered, that will read into the buffer and consume bytes from it without completely emptying it, normal buffer handling can run out of room to read/write into as all the free space is at the head of the buffer. If the amount of data in the buffer is small, you can call .make_room() on the buffered type to make more room for reading. MinBuffered will do this automatically.

Instead of this, with the slice-deque feature, you can instead have your buffered type allocate a ringbuffer, simply by using the ::new_ringbuf() or ::with_capacity_ringbuf() constructors instead of ::new() or with_capacity(), respectively. With a ringbuffer, consuming/flushing bytes from a buffer instantly makes room for more reading/writing at the end. However, this has some caveats:

It is up to you to decide if the benefits outweigh the costs. With a policy like MinBuffered, it could significantly improve performance.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.