How to know if skip_until found byte or not

fn main() {
    use std::io::{self, BufRead};

    let mut cursor = io::Cursor::new(b"hell\n");
    dbg!(cursor.skip_until(b'\n').unwrap());

    let mut cursor = io::Cursor::new(b"hello");
    dbg!(cursor.skip_until(b'\n').unwrap());
}

(Playground)

output:

[src/main.rs:5:5] cursor.skip_until(b'\n').unwrap() = 5
[src/main.rs:8:5] cursor.skip_until(b'\n').unwrap() = 5

How does one tell whether the skip_until() function actually found the byte or not (without using functions outside of the BufRead trait)?

You could use read_until instead and look at the last byte.

That works but it defeats the point of skip_until which doesn't need to allocate memory to store data that won't be used.

I don't see any way clear way to accomplish that

The options to achieve it I see:

If you actually using cursor, use nightly BufRead in std::io - Rust

Implement read_until yourself, and tweak. There is std implementation:



fn skip_until<R: BufRead + ?Sized>(r: &mut R, delim: u8) -> Result<usize> {
    let mut read = 0;
    loop {
        let (done, used) = {
            let available = match r.fill_buf() {
                Ok(n) => n,
                Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
                Err(e) => return Err(e),
            };
            match memchr::memchr(delim, available) {
                Some(i) => (true, i + 1),
                None => (false, available.len()),
            }
        };
        r.consume(used);
        read += used;
        if done || used == 0 {
            return Ok(read);
        }
    }
}
1 Like

How would using has_data_left be sufficient here? Because you could have a newline as the last byte in which case it is not possible to tell them apart.

If you don't mind one final read at the end, you could do it like this:

use std::io::{self, BufRead, Read, Seek};
fn main() {
    let mut cursor = io::Cursor::new(b"hell\n");
    dbg!(cursor.skip_until(b'\n').unwrap());
    dbg!(prev_byte(&mut cursor) == Some(b'\n')); // true

    let mut cursor = io::Cursor::new(b"hello");
    dbg!(cursor.skip_until(b'\n').unwrap());
    dbg!(prev_byte(&mut cursor) == Some(b'\n')); // false
}

fn prev_byte<R: Read + Seek>(mut r: R) -> Option<u8> {
    r.seek_relative(-1).ok()?;
    let mut buf = [0u8; 1];
    r.read(&mut buf).ok()?;
    Some(buf[0])
}
2 Likes