use std::sync::Arc;
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Loc {
pub span: miette::SourceSpan,
pub src: Arc<str>,
}
impl Loc {
pub fn new(span: impl Into<miette::SourceSpan>, src: Arc<str>) -> Self {
Self {
span: span.into(),
src,
}
}
pub fn span(&self, span: impl Into<miette::SourceSpan>) -> Self {
Self {
span: span.into(),
src: Arc::clone(&self.src),
}
}
pub fn start(&self) -> usize {
self.span.offset()
}
pub fn end(&self) -> usize {
self.span.offset() + self.span.len()
}
pub fn snippet(&self) -> Option<&str> {
self.src.get(self.start()..self.end())
}
}
impl From<Loc> for miette::SourceSpan {
fn from(loc: Loc) -> Self {
loc.span
}
}
impl From<&Loc> for miette::SourceSpan {
fn from(loc: &Loc) -> Self {
loc.span
}
}
impl miette::SourceCode for Loc {
fn read_span<'a>(
&'a self,
span: &miette::SourceSpan,
context_lines_before: usize,
context_lines_after: usize,
) -> Result<Box<dyn miette::SpanContents<'a> + 'a>, miette::MietteError> {
self.src
.read_span(span, context_lines_before, context_lines_after)
}
}
impl miette::SourceCode for &Loc {
fn read_span<'a>(
&'a self,
span: &miette::SourceSpan,
context_lines_before: usize,
context_lines_after: usize,
) -> Result<Box<dyn miette::SpanContents<'a> + 'a>, miette::MietteError> {
self.src
.read_span(span, context_lines_before, context_lines_after)
}
}
impl std::fmt::Debug for Loc {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.snippet() {
Some(snippet) => write!(f, r#"Loc(`{snippet}`)"#),
None => write!(
f,
r#"Loc(span: {:?}, src: "{}")"#,
self.span,
self.src.escape_debug()
),
}
}
}
mod test {
#[test]
fn test_loc_debug() {
let str: std::sync::Arc<str> =
r#"permit(principal, action, resource) when { a == b && b == "c" }"#.into();
let l = super::Loc::new(43..49, str.clone());
let l2 = super::Loc::new(53..61, str);
assert_eq!(format!("{l:?}"), r#"Loc(`a == b`)"#);
assert_eq!(format!("{l2:?}"), r#"Loc(`b == "c"`)"#);
}
}