use alloc::vec::Vec;
#[derive(Clone, Debug)]
pub struct LineIndex {
starts: Vec<u32>,
len: u32,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Position {
pub line: u32,
pub column: u32,
}
impl LineIndex {
pub fn new(src: &str) -> Self {
let mut starts = alloc::vec![0u32];
for (i, b) in src.bytes().enumerate() {
if b == b'\n' {
starts.push(u32::try_from(i + 1).unwrap_or(u32::MAX));
}
}
LineIndex {
starts,
len: u32::try_from(src.len()).unwrap_or(u32::MAX),
}
}
pub fn position(&self, src: &str, offset: u32) -> Position {
let offset = offset.min(self.len);
let line = match self.starts.binary_search(&offset) {
Ok(i) => i,
Err(i) => i - 1,
};
let start = self.starts.get(line).copied().unwrap_or(0) as usize;
let column = src
.get(start..offset as usize)
.map_or(0, |s| s.chars().count());
Position {
line: u32::try_from(line + 1).unwrap_or(u32::MAX),
column: u32::try_from(column + 1).unwrap_or(u32::MAX),
}
}
pub fn line_count(&self) -> usize {
self.starts.len()
}
}