I may be missing a subtle point, but to me the proposed Read2
trait:
trait Read2 {
type Data; // = u8; // with associated type defaults.
type Error; // = (); // with associated type defaults.
/// Returns at least 'items', which can be 0 for best-effort.
fn peek(&mut self, items: usize ) -> Result<&[Self::Data],Self::Error>;
/// Can consume any number of items, acting much like `skip()`.
fn consume(&mut self, items: usize ) -> Result<(), Self::Error>;
}
looks awfully similar to the std::io::BufRead
trait:
pub trait BufRead {
/// Fills the internal buffer of this object, returning the buffer contents.
///
/// This function is a lower-level call. It needs to be paired with the consume method to function properly.
/// When calling this method, none of the contents will be "read" in the sense that later calling read may
/// return the same contents. As such, consume must be called with the number of bytes that are
/// consumed from this buffer to ensure that the bytes are never returned twice.
fn fill_buf(&mut self) -> Result<&[u8]>;
/// Tells this buffer that `amt` bytes have been consumed from the buffer,
/// so they should no longer be returned in calls to `read`.
fn consume(&mut self, amt: usize);
...
}
edit: to elaborate a little more, I'd say imo Read
and BufRead
are two approaches to the IO API which mainly differ on who owns the buffer, the caller (for Read
) or the IO construct (for BufRead
).
Depending on the underlying OS APIs, one or the other may be the cheapest (after all, implementing BufRead
directly for a mmaped file rather than on top of Read
makes a lot of sense). But non is intrinsically more general / always better than the other, and both likely are worth having and keeping.