mirror of https://github.com/zkat/miette.git
feat(Source): impl Source for str, &str (make &'static str usable for testing) (#40)
This commit is contained in:
parent
5d5e33d108
commit
50c7a88360
|
|
@ -5,43 +5,73 @@ use std::{borrow::Cow, sync::Arc};
|
||||||
|
|
||||||
use crate::{MietteError, MietteSpanContents, Source, SourceSpan, SpanContents};
|
use crate::{MietteError, MietteSpanContents, Source, SourceSpan, SpanContents};
|
||||||
|
|
||||||
impl Source for String {
|
fn start_line_column(string: &str, span: &SourceSpan) -> Result<(usize, usize), MietteError> {
|
||||||
fn read_span(&self, span: &SourceSpan) -> Result<Box<dyn SpanContents + '_>, MietteError> {
|
let mut offset = 0usize;
|
||||||
let mut offset = 0usize;
|
let mut start_line = 0usize;
|
||||||
let mut start_line = 0usize;
|
let mut start_column = 0usize;
|
||||||
let mut start_column = 0usize;
|
let mut iter = string.chars().peekable();
|
||||||
let mut iter = self.chars().peekable();
|
while let Some(char) = iter.next() {
|
||||||
while let Some(char) = iter.next() {
|
if offset < span.offset() {
|
||||||
if offset < span.offset() {
|
match char {
|
||||||
match char {
|
'\r' => {
|
||||||
'\r' => {
|
if iter.next_if_eq(&'\n').is_some() {
|
||||||
if iter.next_if_eq(&'\n').is_some() {
|
offset += 1;
|
||||||
offset += 1;
|
|
||||||
}
|
|
||||||
start_line += 1;
|
|
||||||
start_column = 0;
|
|
||||||
}
|
|
||||||
'\n' => {
|
|
||||||
start_line += 1;
|
|
||||||
start_column = 0;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
start_column += 1;
|
|
||||||
}
|
}
|
||||||
|
start_line += 1;
|
||||||
|
start_column = 0;
|
||||||
|
}
|
||||||
|
'\n' => {
|
||||||
|
start_line += 1;
|
||||||
|
start_column = 0;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
start_column += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if offset >= span.offset() + span.len() - 1 {
|
|
||||||
return Ok(Box::new(MietteSpanContents::new(
|
|
||||||
&self.as_bytes()[span.offset()..span.offset() + span.len()],
|
|
||||||
start_line,
|
|
||||||
start_column,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += char.len_utf8();
|
|
||||||
}
|
}
|
||||||
Err(MietteError::OutOfBounds)
|
|
||||||
|
if offset >= span.offset() + span.len() - 1 {
|
||||||
|
return Ok((start_line, start_column));
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += char.len_utf8();
|
||||||
|
}
|
||||||
|
Err(MietteError::OutOfBounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The basic impl here is on str (not &str), because otherwise String's impl cannot reuse it
|
||||||
|
// without creating a temporary &str inside its read_span implementation, and then returning data
|
||||||
|
// that refers to that temporary.
|
||||||
|
impl Source for str {
|
||||||
|
fn read_span<'a>(
|
||||||
|
&'a self,
|
||||||
|
span: &SourceSpan,
|
||||||
|
) -> Result<Box<dyn SpanContents + 'a>, MietteError> {
|
||||||
|
let (start_line, start_column) = start_line_column(self, span)?;
|
||||||
|
return Ok(Box::new(MietteSpanContents::new(
|
||||||
|
&self.as_bytes()[span.offset()..span.offset() + span.len()],
|
||||||
|
start_line,
|
||||||
|
start_column,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes `src: &'static str` or `struct S<'a> { src: &'a str }` usable.
|
||||||
|
impl<'s> Source for &'s str {
|
||||||
|
fn read_span<'a>(
|
||||||
|
&'a self,
|
||||||
|
span: &SourceSpan,
|
||||||
|
) -> Result<Box<dyn SpanContents + 'a>, MietteError> {
|
||||||
|
<str as Source>::read_span(self, span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for String {
|
||||||
|
fn read_span<'a>(
|
||||||
|
&'a self,
|
||||||
|
span: &SourceSpan,
|
||||||
|
) -> Result<Box<dyn SpanContents + 'a>, MietteError> {
|
||||||
|
<str as Source>::read_span(self, span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue