diff options
author | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 |
---|---|---|
committer | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 |
commit | 1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch) | |
tree | 7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/miette/src/source_impls.rs | |
parent | 5ecd8cf2cba827454317368b68571df0d13d7842 (diff) | |
download | fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip |
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/miette/src/source_impls.rs')
-rw-r--r-- | vendor/miette/src/source_impls.rs | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/vendor/miette/src/source_impls.rs b/vendor/miette/src/source_impls.rs new file mode 100644 index 0000000..e43a665 --- /dev/null +++ b/vendor/miette/src/source_impls.rs @@ -0,0 +1,301 @@ +/*! +Default trait implementations for [`SourceCode`]. +*/ +use std::{ + borrow::{Cow, ToOwned}, + collections::VecDeque, + fmt::Debug, + sync::Arc, +}; + +use crate::{MietteError, MietteSpanContents, SourceCode, SourceSpan, SpanContents}; + +fn context_info<'a>( + input: &'a [u8], + span: &SourceSpan, + context_lines_before: usize, + context_lines_after: usize, +) -> Result<MietteSpanContents<'a>, MietteError> { + let mut offset = 0usize; + let mut line_count = 0usize; + let mut start_line = 0usize; + let mut start_column = 0usize; + let mut before_lines_starts = VecDeque::new(); + let mut current_line_start = 0usize; + let mut end_lines = 0usize; + let mut post_span = false; + let mut post_span_got_newline = false; + let mut iter = input.iter().copied().peekable(); + while let Some(char) = iter.next() { + if matches!(char, b'\r' | b'\n') { + line_count += 1; + if char == b'\r' && iter.next_if_eq(&b'\n').is_some() { + offset += 1; + } + if offset < span.offset() { + // We're before the start of the span. + start_column = 0; + before_lines_starts.push_back(current_line_start); + if before_lines_starts.len() > context_lines_before { + start_line += 1; + before_lines_starts.pop_front(); + } + } else if offset >= span.offset() + span.len().saturating_sub(1) { + // We're after the end of the span, but haven't necessarily + // started collecting end lines yet (we might still be + // collecting context lines). + if post_span { + start_column = 0; + if post_span_got_newline { + end_lines += 1; + } else { + post_span_got_newline = true; + } + if end_lines >= context_lines_after { + offset += 1; + break; + } + } + } + current_line_start = offset + 1; + } else if offset < span.offset() { + start_column += 1; + } + + if offset >= (span.offset() + span.len()).saturating_sub(1) { + post_span = true; + if end_lines >= context_lines_after { + offset += 1; + break; + } + } + + offset += 1; + } + + if offset >= (span.offset() + span.len()).saturating_sub(1) { + let starting_offset = before_lines_starts.front().copied().unwrap_or_else(|| { + if context_lines_before == 0 { + span.offset() + } else { + 0 + } + }); + Ok(MietteSpanContents::new( + &input[starting_offset..offset], + (starting_offset, offset - starting_offset).into(), + start_line, + if context_lines_before == 0 { + start_column + } else { + 0 + }, + line_count, + )) + } else { + Err(MietteError::OutOfBounds) + } +} + +impl SourceCode for [u8] { + fn read_span<'a>( + &'a self, + span: &SourceSpan, + context_lines_before: usize, + context_lines_after: usize, + ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> { + let contents = context_info(self, span, context_lines_before, context_lines_after)?; + Ok(Box::new(contents)) + } +} + +impl<'src> SourceCode for &'src [u8] { + fn read_span<'a>( + &'a self, + span: &SourceSpan, + context_lines_before: usize, + context_lines_after: usize, + ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> { + <[u8] as SourceCode>::read_span(self, span, context_lines_before, context_lines_after) + } +} + +impl SourceCode for Vec<u8> { + fn read_span<'a>( + &'a self, + span: &SourceSpan, + context_lines_before: usize, + context_lines_after: usize, + ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> { + <[u8] as SourceCode>::read_span(self, span, context_lines_before, context_lines_after) + } +} + +impl SourceCode for str { + fn read_span<'a>( + &'a self, + span: &SourceSpan, + context_lines_before: usize, + context_lines_after: usize, + ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> { + <[u8] as SourceCode>::read_span( + self.as_bytes(), + span, + context_lines_before, + context_lines_after, + ) + } +} + +/// Makes `src: &'static str` or `struct S<'a> { src: &'a str }` usable. +impl<'s> SourceCode for &'s str { + fn read_span<'a>( + &'a self, + span: &SourceSpan, + context_lines_before: usize, + context_lines_after: usize, + ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> { + <str as SourceCode>::read_span(self, span, context_lines_before, context_lines_after) + } +} + +impl SourceCode for String { + fn read_span<'a>( + &'a self, + span: &SourceSpan, + context_lines_before: usize, + context_lines_after: usize, + ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> { + <str as SourceCode>::read_span(self, span, context_lines_before, context_lines_after) + } +} + +impl<T: ?Sized + SourceCode> SourceCode for Arc<T> { + fn read_span<'a>( + &'a self, + span: &SourceSpan, + context_lines_before: usize, + context_lines_after: usize, + ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> { + self.as_ref() + .read_span(span, context_lines_before, context_lines_after) + } +} + +impl<T: ?Sized + SourceCode + ToOwned> SourceCode for Cow<'_, T> +where + // The minimal bounds are used here. + // `T::Owned` need not be + // `SourceCode`, because `&T` + // can always be obtained from + // `Cow<'_, T>`. + T::Owned: Debug + Send + Sync, +{ + fn read_span<'a>( + &'a self, + span: &SourceSpan, + context_lines_before: usize, + context_lines_after: usize, + ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> { + self.as_ref() + .read_span(span, context_lines_before, context_lines_after) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn basic() -> Result<(), MietteError> { + let src = String::from("foo\n"); + let contents = src.read_span(&(0, 4).into(), 0, 0)?; + assert_eq!("foo\n", std::str::from_utf8(contents.data()).unwrap()); + assert_eq!(0, contents.line()); + assert_eq!(0, contents.column()); + Ok(()) + } + + #[test] + fn shifted() -> Result<(), MietteError> { + let src = String::from("foobar"); + let contents = src.read_span(&(3, 3).into(), 1, 1)?; + assert_eq!("foobar", std::str::from_utf8(contents.data()).unwrap()); + assert_eq!(0, contents.line()); + assert_eq!(0, contents.column()); + Ok(()) + } + + #[test] + fn middle() -> Result<(), MietteError> { + let src = String::from("foo\nbar\nbaz\n"); + let contents = src.read_span(&(4, 4).into(), 0, 0)?; + assert_eq!("bar\n", std::str::from_utf8(contents.data()).unwrap()); + assert_eq!(1, contents.line()); + assert_eq!(0, contents.column()); + Ok(()) + } + + #[test] + fn middle_of_line() -> Result<(), MietteError> { + let src = String::from("foo\nbarbar\nbaz\n"); + let contents = src.read_span(&(7, 4).into(), 0, 0)?; + assert_eq!("bar\n", std::str::from_utf8(contents.data()).unwrap()); + assert_eq!(1, contents.line()); + assert_eq!(3, contents.column()); + Ok(()) + } + + #[test] + fn with_crlf() -> Result<(), MietteError> { + let src = String::from("foo\r\nbar\r\nbaz\r\n"); + let contents = src.read_span(&(5, 5).into(), 0, 0)?; + assert_eq!("bar\r\n", std::str::from_utf8(contents.data()).unwrap()); + assert_eq!(1, contents.line()); + assert_eq!(0, contents.column()); + Ok(()) + } + + #[test] + fn with_context() -> Result<(), MietteError> { + let src = String::from("xxx\nfoo\nbar\nbaz\n\nyyy\n"); + let contents = src.read_span(&(8, 3).into(), 1, 1)?; + assert_eq!( + "foo\nbar\nbaz\n", + std::str::from_utf8(contents.data()).unwrap() + ); + assert_eq!(1, contents.line()); + assert_eq!(0, contents.column()); + Ok(()) + } + + #[test] + fn multiline_with_context() -> Result<(), MietteError> { + let src = String::from("aaa\nxxx\n\nfoo\nbar\nbaz\n\nyyy\nbbb\n"); + let contents = src.read_span(&(9, 11).into(), 1, 1)?; + assert_eq!( + "\nfoo\nbar\nbaz\n\n", + std::str::from_utf8(contents.data()).unwrap() + ); + assert_eq!(2, contents.line()); + assert_eq!(0, contents.column()); + let span: SourceSpan = (8, 14).into(); + assert_eq!(&span, contents.span()); + Ok(()) + } + + #[test] + fn multiline_with_context_line_start() -> Result<(), MietteError> { + let src = String::from("one\ntwo\n\nthree\nfour\nfive\n\nsix\nseven\n"); + let contents = src.read_span(&(2, 0).into(), 2, 2)?; + assert_eq!( + "one\ntwo\n\n", + std::str::from_utf8(contents.data()).unwrap() + ); + assert_eq!(0, contents.line()); + assert_eq!(0, contents.column()); + let span: SourceSpan = (0, 9).into(); + assert_eq!(&span, contents.span()); + Ok(()) + } +} |