use {
crate::{line_col, Loc, Span},
::core::{
fmt::Debug,
hash::{Hash, Hasher},
ops::{Index, Range},
},
};
pub trait BufferSource: Debug + Default {
fn source(&self) -> &str;
fn name(&self) -> Option<&str> {
None
}
}
impl BufferSource for String {
fn source(&self) -> &str {
self
}
}
#[derive(Debug)]
pub struct Buffer<Src: BufferSource> {
pub(crate) index: u16,
pub linear_span: Range<usize>,
pub src: Src,
pub line_beginnings: Vec<u32>,
}
impl<Src: BufferSource> Buffer<Src> {
pub fn start(&self) -> Loc {
Loc {
buf: self.index,
pos: 0,
}
}
#[allow(clippy::cast_possible_truncation, reason = "documented")]
pub fn end(&self) -> Loc {
Loc {
buf: self.index,
pos: self.len() as u32,
}
}
#[allow(clippy::cast_possible_truncation, reason = "documented")]
pub fn span(&self) -> Span {
Span {
start: 0,
end: self.src.source().len() as u32,
buf: self.index,
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn len(&self) -> usize {
self.src.source().len()
}
pub fn len_lines(&self) -> usize {
self.line_beginnings.len()
}
#[allow(clippy::cast_possible_truncation, reason = "documented")]
pub fn contains(&self, loc: Loc) -> bool {
loc.buf == self.index && loc.pos < self.len() as u32
}
#[allow(clippy::cast_possible_truncation, reason = "documented")]
pub fn contains_span(&self, span: Span) -> bool {
span.buf == self.index && span.end <= self.len() as u32
}
pub fn src_slice(&self, span: Span) -> &str {
&self[span]
}
pub fn loc_of(&self, line_col: &line_col::LineCol) -> Loc {
Loc {
pos: self.line_beginnings[line_col.line as usize] + line_col.col,
buf: self.index,
}
}
pub fn line_col(&self, loc: Loc) -> line_col::LineCol {
assert_eq!(
loc.buf, self.index,
"looking up line_col for a position in a different buffer"
);
line_col::find_line_col(&self.line_beginnings[..], loc.pos)
}
}
impl<Src: BufferSource> Index<Span> for Buffer<Src> {
type Output = str;
fn index(&self, span: Span) -> &Self::Output {
assert_eq!(
span.buf, self.index,
"looking up line_col for a position in a different buffer"
);
&self.src.source()[span.start as usize..span.end as usize]
}
}
impl<Src: BufferSource> Hash for Buffer<Src> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.index.hash(state);
}
}
impl<Src: BufferSource> PartialEq for Buffer<Src> {
fn eq(&self, rhs: &Self) -> bool {
self.index == rhs.index
}
}
impl<Src: BufferSource> Eq for Buffer<Src> {}