feat(Source): impl Source for str, &str (make &'static str usable for testing) (#40)

This commit is contained in:
Cormac Relf 2021-08-30 12:07:07 +10:00 committed by GitHub
parent 5d5e33d108
commit 50c7a88360
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 63 additions and 33 deletions

View File

@ -5,43 +5,73 @@ use std::{borrow::Cow, sync::Arc};
use crate::{MietteError, MietteSpanContents, Source, SourceSpan, SpanContents};
impl Source for String {
fn read_span(&self, span: &SourceSpan) -> Result<Box<dyn SpanContents + '_>, MietteError> {
let mut offset = 0usize;
let mut start_line = 0usize;
let mut start_column = 0usize;
let mut iter = self.chars().peekable();
while let Some(char) = iter.next() {
if offset < span.offset() {
match char {
'\r' => {
if iter.next_if_eq(&'\n').is_some() {
offset += 1;
}
start_line += 1;
start_column = 0;
}
'\n' => {
start_line += 1;
start_column = 0;
}
_ => {
start_column += 1;
fn start_line_column(string: &str, span: &SourceSpan) -> Result<(usize, usize), MietteError> {
let mut offset = 0usize;
let mut start_line = 0usize;
let mut start_column = 0usize;
let mut iter = string.chars().peekable();
while let Some(char) = iter.next() {
if offset < span.offset() {
match char {
'\r' => {
if iter.next_if_eq(&'\n').is_some() {
offset += 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)
}
}