pub(crate) fn start_of_line(buf: &str, pos: usize) -> usize {
buf[..pos].rfind('\n').map_or(0, |i| i + 1)
}
pub(crate) fn end_of_line(buf: &str, pos: usize) -> usize {
match buf[pos..].find('\n') {
None => buf.len(),
Some(i) => {
let newline = pos + i;
if newline > 0 && buf.as_bytes()[newline - 1] == b'\r' {
newline - 1
} else {
newline
}
}
}
}
pub(crate) fn start_of_next_line(buf: &str, pos: usize) -> Option<usize> {
buf[pos..].find('\n').map(|i| pos + i + 1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn start_of_line_finds_current_line() {
assert_eq!(start_of_line("ab\ncd\nef", 0), 0);
assert_eq!(start_of_line("ab\ncd\nef", 2), 0); assert_eq!(start_of_line("ab\ncd\nef", 4), 3);
assert_eq!(start_of_line("ab\ncd\nef", 8), 6);
}
#[test]
fn end_of_line_stops_at_newline_or_buffer_end() {
assert_eq!(end_of_line("ab\ncd\nef", 0), 2);
assert_eq!(end_of_line("ab\ncd\nef", 4), 5);
assert_eq!(end_of_line("ab\ncd\nef", 7), 8); }
#[test]
fn end_of_line_backs_over_carriage_return() {
assert_eq!(end_of_line("ab\r\ncd", 0), 2);
assert_eq!(end_of_line("ab\r\ncd", 5), 6);
}
#[test]
fn start_of_next_line_is_none_on_last_line() {
assert_eq!(start_of_next_line("ab\ncd", 0), Some(3));
assert_eq!(start_of_next_line("ab\ncd", 4), None);
assert_eq!(start_of_next_line("ab\r\ncd", 0), Some(4));
}
}