1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

split: add forwards_thru_file() helper function

Add helper function `forwards_thru_file()` that finds the index in a
reader of the byte immediately following the `n`th instance of a given
byte.
This commit is contained in:
Jeffrey Finkelstein 2022-01-21 13:26:10 -05:00
parent 8c298e97a5
commit d27d6bc32c

View file

@ -386,6 +386,83 @@ fn follow<T: BufRead>(readers: &mut [(T, &String)], settings: &Settings) -> URes
Ok(())
}
/// Find the index after the given number of instances of a given byte.
///
/// This function reads through a given reader until `num_delimiters`
/// instances of `delimiter` have been seen, returning the index of
/// the byte immediately following that delimiter. If there are fewer
/// than `num_delimiters` instances of `delimiter`, this returns the
/// total number of bytes read from the `reader` until EOF.
///
/// # Errors
///
/// This function returns an error if there is an error during reading
/// from `reader`.
///
/// # Examples
///
/// Basic usage:
///
/// ```rust,ignore
/// use std::io::Cursor;
///
/// let mut reader = Cursor::new("a\nb\nc\nd\ne\n");
/// let i = forwards_thru_file(&mut reader, 2, b'\n').unwrap();
/// assert_eq!(i, 4);
/// ```
///
/// If `num_delimiters` is zero, then this function always returns
/// zero:
///
/// ```rust,ignore
/// use std::io::Cursor;
///
/// let mut reader = Cursor::new("a\n");
/// let i = forwards_thru_file(&mut reader, 0, b'\n').unwrap();
/// assert_eq!(i, 0);
/// ```
///
/// If there are fewer than `num_delimiters` instances of `delimiter`
/// in the reader, then this function returns the total number of
/// bytes read:
///
/// ```rust,ignore
/// use std::io::Cursor;
///
/// let mut reader = Cursor::new("a\n");
/// let i = forwards_thru_file(&mut reader, 2, b'\n').unwrap();
/// assert_eq!(i, 2);
/// ```
fn forwards_thru_file<R>(
reader: &mut R,
num_delimiters: usize,
delimiter: u8,
) -> std::io::Result<usize>
where
R: Read,
{
let mut reader = BufReader::new(reader);
let mut buf = vec![];
let mut total = 0;
for _ in 0..num_delimiters {
match reader.read_until(delimiter, &mut buf) {
Ok(0) => {
return Ok(total);
}
Ok(n) => {
total += n;
buf.clear();
continue;
}
Err(e) => {
return Err(e);
}
}
}
Ok(total)
}
/// Iterate over bytes in the file, in reverse, until we find the
/// `num_delimiters` instance of `delimiter`. The `file` is left seek'd to the
/// position just after that delimiter.
@ -534,3 +611,32 @@ fn get_block_size(md: &Metadata) -> u64 {
md.len()
}
}
#[cfg(test)]
mod tests {
use crate::forwards_thru_file;
use std::io::Cursor;
#[test]
fn test_forwards_thru_file_zero() {
let mut reader = Cursor::new("a\n");
let i = forwards_thru_file(&mut reader, 0, b'\n').unwrap();
assert_eq!(i, 0);
}
#[test]
fn test_forwards_thru_file_basic() {
// 01 23 45 67 89
let mut reader = Cursor::new("a\nb\nc\nd\ne\n");
let i = forwards_thru_file(&mut reader, 2, b'\n').unwrap();
assert_eq!(i, 4);
}
#[test]
fn test_forwards_thru_file_past_end() {
let mut reader = Cursor::new("x\n");
let i = forwards_thru_file(&mut reader, 2, b'\n').unwrap();
assert_eq!(i, 2);
}
}