Rust beginner notes & questions

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.

4 Likes