#![no_std]
extern crate alloc;
use alloc::vec::Vec;
#[derive(Clone, Debug)]
pub struct LineCache(Vec<(usize, usize)>);
impl LineCache {
pub fn new(s: &str) -> Self {
Self(
s.bytes()
.enumerate()
.filter(|&(_, i)| i == b'\n')
.enumerate()
.map(|(lnr, (bkpt, _))| (lnr + 1, bkpt))
.collect(),
)
}
pub fn run(&self, pos: usize) -> (usize, usize) {
let (lnr, bkpt) = self
.0
.iter()
.copied()
.take_while(|&(_, bkpt)| bkpt <= pos)
.last()
.unwrap_or((0, 0));
(lnr, pos - bkpt)
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct PosTrackerExtern {
offset: usize,
line: usize,
column: usize,
}
impl PosTrackerExtern {
pub fn update<'a>(
&mut self,
dat: &'a [u8],
new_offset: usize,
) -> Option<(&'a [u8], usize, usize)> {
new_offset.checked_sub(self.offset)?;
let mut ldif = 0;
let mut cdif = 0;
let slc = &dat[self.offset..new_offset];
for &i in slc {
if i == b'\n' {
cdif = 0;
ldif += 1;
} else if i != b'\r' {
cdif += 1;
}
}
self.offset = new_offset;
self.line += ldif;
if ldif != 0 {
self.column = 0;
}
self.column += cdif;
Some((slc, ldif, cdif))
}
}
#[derive(Clone, Copy, Debug)]
pub struct PosTrackerDatRef<'a> {
dat: &'a [u8],
inner: PosTrackerExtern,
}
impl<'a> PosTrackerDatRef<'a> {
#[inline]
pub fn new(dat: &'a [u8]) -> Self {
Self {
dat,
inner: Default::default(),
}
}
#[inline(always)]
pub fn inner(&self) -> PosTrackerExtern {
self.inner
}
#[inline]
pub fn update(&mut self, new_offset: usize) -> Option<(&'a [u8], usize, usize)> {
self.inner.update(self.dat, new_offset)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_source_location() {
const SRC: &str = r#"Das ist ein Test!
Hurra!
"#;
let lc = LineCache::new(SRC);
assert_eq!(lc.0, alloc::vec![(1, 17), (2, 24)]);
assert_eq!(lc.run(3), (0, 3));
assert_eq!(lc.run(20), (1, 3));
}
}