diff options
Diffstat (limited to 'vendor/miette/src/protocol.rs')
-rw-r--r-- | vendor/miette/src/protocol.rs | 697 |
1 files changed, 0 insertions, 697 deletions
diff --git a/vendor/miette/src/protocol.rs b/vendor/miette/src/protocol.rs deleted file mode 100644 index f516984..0000000 --- a/vendor/miette/src/protocol.rs +++ /dev/null @@ -1,697 +0,0 @@ -/*! -This module defines the core of the miette protocol: a series of types and -traits that you can implement to get access to miette's (and related library's) -full reporting and such features. -*/ -use std::{ - fmt::{self, Display}, - fs, - panic::Location, -}; - -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -use crate::MietteError; - -/// Adds rich metadata to your Error that can be used by -/// [`Report`](crate::Report) to print really nice and human-friendly error -/// messages. -pub trait Diagnostic: std::error::Error { - /// Unique diagnostic code that can be used to look up more information - /// about this `Diagnostic`. Ideally also globally unique, and documented - /// in the toplevel crate's documentation for easy searching. Rust path - /// format (`foo::bar::baz`) is recommended, but more classic codes like - /// `E0123` or enums will work just fine. - fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> { - None - } - - /// Diagnostic severity. This may be used by - /// [`ReportHandler`](crate::ReportHandler)s to change the display format - /// of this diagnostic. - /// - /// If `None`, reporters should treat this as [`Severity::Error`]. - fn severity(&self) -> Option<Severity> { - None - } - - /// Additional help text related to this `Diagnostic`. Do you have any - /// advice for the poor soul who's just run into this issue? - fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> { - None - } - - /// URL to visit for a more detailed explanation/help about this - /// `Diagnostic`. - fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> { - None - } - - /// Source code to apply this `Diagnostic`'s [`Diagnostic::labels`] to. - fn source_code(&self) -> Option<&dyn SourceCode> { - None - } - - /// Labels to apply to this `Diagnostic`'s [`Diagnostic::source_code`] - fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> { - None - } - - /// Additional related `Diagnostic`s. - fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> { - None - } - - /// The cause of the error. - fn diagnostic_source(&self) -> Option<&dyn Diagnostic> { - None - } -} - -macro_rules! box_impls { - ($($box_type:ty),*) => { - $( - impl std::error::Error for $box_type { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - (**self).source() - } - - fn cause(&self) -> Option<&dyn std::error::Error> { - self.source() - } - } - )* - } -} - -box_impls! { - Box<dyn Diagnostic>, - Box<dyn Diagnostic + Send>, - Box<dyn Diagnostic + Send + Sync> -} - -impl<T: Diagnostic + Send + Sync + 'static> From<T> - for Box<dyn Diagnostic + Send + Sync + 'static> -{ - fn from(diag: T) -> Self { - Box::new(diag) - } -} - -impl<T: Diagnostic + Send + Sync + 'static> From<T> for Box<dyn Diagnostic + Send + 'static> { - fn from(diag: T) -> Self { - Box::<dyn Diagnostic + Send + Sync>::from(diag) - } -} - -impl<T: Diagnostic + Send + Sync + 'static> From<T> for Box<dyn Diagnostic + 'static> { - fn from(diag: T) -> Self { - Box::<dyn Diagnostic + Send + Sync>::from(diag) - } -} - -impl From<&str> for Box<dyn Diagnostic> { - fn from(s: &str) -> Self { - From::from(String::from(s)) - } -} - -impl<'a> From<&str> for Box<dyn Diagnostic + Send + Sync + 'a> { - fn from(s: &str) -> Self { - From::from(String::from(s)) - } -} - -impl From<String> for Box<dyn Diagnostic> { - fn from(s: String) -> Self { - let err1: Box<dyn Diagnostic + Send + Sync> = From::from(s); - let err2: Box<dyn Diagnostic> = err1; - err2 - } -} - -impl From<String> for Box<dyn Diagnostic + Send + Sync> { - fn from(s: String) -> Self { - struct StringError(String); - - impl std::error::Error for StringError {} - impl Diagnostic for StringError {} - - impl Display for StringError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&self.0, f) - } - } - - // Purposefully skip printing "StringError(..)" - impl fmt::Debug for StringError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } - } - - Box::new(StringError(s)) - } -} - -impl From<Box<dyn std::error::Error + Send + Sync>> for Box<dyn Diagnostic + Send + Sync> { - fn from(s: Box<dyn std::error::Error + Send + Sync>) -> Self { - #[derive(thiserror::Error)] - #[error(transparent)] - struct BoxedDiagnostic(Box<dyn std::error::Error + Send + Sync>); - impl fmt::Debug for BoxedDiagnostic { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } - } - - impl Diagnostic for BoxedDiagnostic {} - - Box::new(BoxedDiagnostic(s)) - } -} - -/** -[`Diagnostic`] severity. Intended to be used by -[`ReportHandler`](crate::ReportHandler)s to change the way different -[`Diagnostic`]s are displayed. Defaults to [`Severity::Error`]. -*/ -#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum Severity { - /// Just some help. Here's how you could be doing it better. - Advice, - /// Warning. Please take note. - Warning, - /// Critical failure. The program cannot continue. - /// This is the default severity, if you don't specify another one. - Error, -} - -impl Default for Severity { - fn default() -> Self { - Severity::Error - } -} - -#[cfg(feature = "serde")] -#[test] -fn test_serialize_severity() { - use serde_json::json; - - assert_eq!(json!(Severity::Advice), json!("Advice")); - assert_eq!(json!(Severity::Warning), json!("Warning")); - assert_eq!(json!(Severity::Error), json!("Error")); -} - -#[cfg(feature = "serde")] -#[test] -fn test_deserialize_severity() { - use serde_json::json; - - let severity: Severity = serde_json::from_value(json!("Advice")).unwrap(); - assert_eq!(severity, Severity::Advice); - - let severity: Severity = serde_json::from_value(json!("Warning")).unwrap(); - assert_eq!(severity, Severity::Warning); - - let severity: Severity = serde_json::from_value(json!("Error")).unwrap(); - assert_eq!(severity, Severity::Error); -} - -/** -Represents readable source code of some sort. - -This trait is able to support simple `SourceCode` types like [`String`]s, as -well as more involved types like indexes into centralized `SourceMap`-like -types, file handles, and even network streams. - -If you can read it, you can source it, and it's not necessary to read the -whole thing--meaning you should be able to support `SourceCode`s which are -gigabytes or larger in size. -*/ -pub trait SourceCode: Send + Sync { - /// Read the bytes for a specific span from this SourceCode, keeping a - /// certain number of lines before and after the span as context. - fn read_span<'a>( - &'a self, - span: &SourceSpan, - context_lines_before: usize, - context_lines_after: usize, - ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError>; -} - -/// A labeled [`SourceSpan`]. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct LabeledSpan { - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] - label: Option<String>, - span: SourceSpan, -} - -impl LabeledSpan { - /// Makes a new labeled span. - pub const fn new(label: Option<String>, offset: ByteOffset, len: usize) -> Self { - Self { - label, - span: SourceSpan::new(SourceOffset(offset), SourceOffset(len)), - } - } - - /// Makes a new labeled span using an existing span. - pub fn new_with_span(label: Option<String>, span: impl Into<SourceSpan>) -> Self { - Self { - label, - span: span.into(), - } - } - - /// Makes a new label at specified span - /// - /// # Examples - /// ``` - /// use miette::LabeledSpan; - /// - /// let source = "Cpp is the best"; - /// let label = LabeledSpan::at(0..3, "should be Rust"); - /// assert_eq!( - /// label, - /// LabeledSpan::new(Some("should be Rust".to_string()), 0, 3) - /// ) - /// ``` - pub fn at(span: impl Into<SourceSpan>, label: impl Into<String>) -> Self { - Self::new_with_span(Some(label.into()), span) - } - - /// Makes a new label that points at a specific offset. - /// - /// # Examples - /// ``` - /// use miette::LabeledSpan; - /// - /// let source = "(2 + 2"; - /// let label = LabeledSpan::at_offset(4, "expected a closing parenthesis"); - /// assert_eq!( - /// label, - /// LabeledSpan::new(Some("expected a closing parenthesis".to_string()), 4, 0) - /// ) - /// ``` - pub fn at_offset(offset: ByteOffset, label: impl Into<String>) -> Self { - Self::new(Some(label.into()), offset, 0) - } - - /// Makes a new label without text, that underlines a specific span. - /// - /// # Examples - /// ``` - /// use miette::LabeledSpan; - /// - /// let source = "You have an eror here"; - /// let label = LabeledSpan::underline(12..16); - /// assert_eq!(label, LabeledSpan::new(None, 12, 4)) - /// ``` - pub fn underline(span: impl Into<SourceSpan>) -> Self { - Self::new_with_span(None, span) - } - - /// Gets the (optional) label string for this `LabeledSpan`. - pub fn label(&self) -> Option<&str> { - self.label.as_deref() - } - - /// Returns a reference to the inner [`SourceSpan`]. - pub const fn inner(&self) -> &SourceSpan { - &self.span - } - - /// Returns the 0-based starting byte offset. - pub const fn offset(&self) -> usize { - self.span.offset() - } - - /// Returns the number of bytes this `LabeledSpan` spans. - pub const fn len(&self) -> usize { - self.span.len() - } - - /// True if this `LabeledSpan` is empty. - pub const fn is_empty(&self) -> bool { - self.span.is_empty() - } -} - -#[cfg(feature = "serde")] -#[test] -fn test_serialize_labeled_span() { - use serde_json::json; - - assert_eq!( - json!(LabeledSpan::new(None, 0, 0)), - json!({ - "span": { "offset": 0, "length": 0 } - }) - ); - - assert_eq!( - json!(LabeledSpan::new(Some("label".to_string()), 0, 0)), - json!({ - "label": "label", - "span": { "offset": 0, "length": 0 } - }) - ) -} - -#[cfg(feature = "serde")] -#[test] -fn test_deserialize_labeled_span() { - use serde_json::json; - - let span: LabeledSpan = serde_json::from_value(json!({ - "label": null, - "span": { "offset": 0, "length": 0 } - })) - .unwrap(); - assert_eq!(span, LabeledSpan::new(None, 0, 0)); - - let span: LabeledSpan = serde_json::from_value(json!({ - "span": { "offset": 0, "length": 0 } - })) - .unwrap(); - assert_eq!(span, LabeledSpan::new(None, 0, 0)); - - let span: LabeledSpan = serde_json::from_value(json!({ - "label": "label", - "span": { "offset": 0, "length": 0 } - })) - .unwrap(); - assert_eq!(span, LabeledSpan::new(Some("label".to_string()), 0, 0)) -} - -/** -Contents of a [`SourceCode`] covered by [`SourceSpan`]. - -Includes line and column information to optimize highlight calculations. -*/ -pub trait SpanContents<'a> { - /// Reference to the data inside the associated span, in bytes. - fn data(&self) -> &'a [u8]; - /// [`SourceSpan`] representing the span covered by this `SpanContents`. - fn span(&self) -> &SourceSpan; - /// An optional (file?) name for the container of this `SpanContents`. - fn name(&self) -> Option<&str> { - None - } - /// The 0-indexed line in the associated [`SourceCode`] where the data - /// begins. - fn line(&self) -> usize; - /// The 0-indexed column in the associated [`SourceCode`] where the data - /// begins, relative to `line`. - fn column(&self) -> usize; - /// Total number of lines covered by this `SpanContents`. - fn line_count(&self) -> usize; -} - -/** -Basic implementation of the [`SpanContents`] trait, for convenience. -*/ -#[derive(Clone, Debug)] -pub struct MietteSpanContents<'a> { - // Data from a [`SourceCode`], in bytes. - data: &'a [u8], - // span actually covered by this SpanContents. - span: SourceSpan, - // The 0-indexed line where the associated [`SourceSpan`] _starts_. - line: usize, - // The 0-indexed column where the associated [`SourceSpan`] _starts_. - column: usize, - // Number of line in this snippet. - line_count: usize, - // Optional filename - name: Option<String>, -} - -impl<'a> MietteSpanContents<'a> { - /// Make a new [`MietteSpanContents`] object. - pub const fn new( - data: &'a [u8], - span: SourceSpan, - line: usize, - column: usize, - line_count: usize, - ) -> MietteSpanContents<'a> { - MietteSpanContents { - data, - span, - line, - column, - line_count, - name: None, - } - } - - /// Make a new [`MietteSpanContents`] object, with a name for its 'file'. - pub const fn new_named( - name: String, - data: &'a [u8], - span: SourceSpan, - line: usize, - column: usize, - line_count: usize, - ) -> MietteSpanContents<'a> { - MietteSpanContents { - data, - span, - line, - column, - line_count, - name: Some(name), - } - } -} - -impl<'a> SpanContents<'a> for MietteSpanContents<'a> { - fn data(&self) -> &'a [u8] { - self.data - } - fn span(&self) -> &SourceSpan { - &self.span - } - fn line(&self) -> usize { - self.line - } - fn column(&self) -> usize { - self.column - } - fn line_count(&self) -> usize { - self.line_count - } - fn name(&self) -> Option<&str> { - self.name.as_deref() - } -} - -/// Span within a [`SourceCode`] -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct SourceSpan { - /// The start of the span. - offset: SourceOffset, - /// The total length of the span - length: usize, -} - -impl SourceSpan { - /// Create a new [`SourceSpan`]. - pub const fn new(start: SourceOffset, length: SourceOffset) -> Self { - Self { - offset: start, - length: length.offset(), - } - } - - /// The absolute offset, in bytes, from the beginning of a [`SourceCode`]. - pub const fn offset(&self) -> usize { - self.offset.offset() - } - - /// Total length of the [`SourceSpan`], in bytes. - pub const fn len(&self) -> usize { - self.length - } - - /// Whether this [`SourceSpan`] has a length of zero. It may still be useful - /// to point to a specific point. - pub const fn is_empty(&self) -> bool { - self.length == 0 - } -} - -impl From<(ByteOffset, usize)> for SourceSpan { - fn from((start, len): (ByteOffset, usize)) -> Self { - Self { - offset: start.into(), - length: len, - } - } -} - -impl From<(SourceOffset, SourceOffset)> for SourceSpan { - fn from((start, len): (SourceOffset, SourceOffset)) -> Self { - Self::new(start, len) - } -} - -impl From<std::ops::Range<ByteOffset>> for SourceSpan { - fn from(range: std::ops::Range<ByteOffset>) -> Self { - Self { - offset: range.start.into(), - length: range.len(), - } - } -} - -impl From<SourceOffset> for SourceSpan { - fn from(offset: SourceOffset) -> Self { - Self { offset, length: 0 } - } -} - -impl From<ByteOffset> for SourceSpan { - fn from(offset: ByteOffset) -> Self { - Self { - offset: offset.into(), - length: 0, - } - } -} - -#[cfg(feature = "serde")] -#[test] -fn test_serialize_source_span() { - use serde_json::json; - - assert_eq!( - json!(SourceSpan::from(0)), - json!({ "offset": 0, "length": 0}) - ) -} - -#[cfg(feature = "serde")] -#[test] -fn test_deserialize_source_span() { - use serde_json::json; - - let span: SourceSpan = serde_json::from_value(json!({ "offset": 0, "length": 0})).unwrap(); - assert_eq!(span, SourceSpan::from(0)) -} - -/** -"Raw" type for the byte offset from the beginning of a [`SourceCode`]. -*/ -pub type ByteOffset = usize; - -/** -Newtype that represents the [`ByteOffset`] from the beginning of a [`SourceCode`] -*/ -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct SourceOffset(ByteOffset); - -impl SourceOffset { - /// Actual byte offset. - pub const fn offset(&self) -> ByteOffset { - self.0 - } - - /// Little utility to help convert 1-based line/column locations into - /// miette-compatible Spans - /// - /// This function is infallible: Giving an out-of-range line/column pair - /// will return the offset of the last byte in the source. - pub fn from_location(source: impl AsRef<str>, loc_line: usize, loc_col: usize) -> Self { - let mut line = 0usize; - let mut col = 0usize; - let mut offset = 0usize; - for char in source.as_ref().chars() { - if line + 1 >= loc_line && col + 1 >= loc_col { - break; - } - if char == '\n' { - col = 0; - line += 1; - } else { - col += 1; - } - offset += char.len_utf8(); - } - - SourceOffset(offset) - } - - /// Returns an offset for the _file_ location of wherever this function is - /// called. If you want to get _that_ caller's location, mark this - /// function's caller with `#[track_caller]` (and so on and so forth). - /// - /// Returns both the filename that was given and the offset of the caller - /// as a [`SourceOffset`]. - /// - /// Keep in mind that this fill only work if the file your Rust source - /// file was compiled from is actually available at that location. If - /// you're shipping binaries for your application, you'll want to ignore - /// the Err case or otherwise report it. - #[track_caller] - pub fn from_current_location() -> Result<(String, Self), MietteError> { - let loc = Location::caller(); - Ok(( - loc.file().into(), - fs::read_to_string(loc.file()) - .map(|txt| Self::from_location(txt, loc.line() as usize, loc.column() as usize))?, - )) - } -} - -impl From<ByteOffset> for SourceOffset { - fn from(bytes: ByteOffset) -> Self { - SourceOffset(bytes) - } -} - -#[test] -fn test_source_offset_from_location() { - let source = "f\n\noo\r\nbar"; - - assert_eq!(SourceOffset::from_location(source, 1, 1).offset(), 0); - assert_eq!(SourceOffset::from_location(source, 1, 2).offset(), 1); - assert_eq!(SourceOffset::from_location(source, 2, 1).offset(), 2); - assert_eq!(SourceOffset::from_location(source, 3, 1).offset(), 3); - assert_eq!(SourceOffset::from_location(source, 3, 2).offset(), 4); - assert_eq!(SourceOffset::from_location(source, 3, 3).offset(), 5); - assert_eq!(SourceOffset::from_location(source, 3, 4).offset(), 6); - assert_eq!(SourceOffset::from_location(source, 4, 1).offset(), 7); - assert_eq!(SourceOffset::from_location(source, 4, 2).offset(), 8); - assert_eq!(SourceOffset::from_location(source, 4, 3).offset(), 9); - assert_eq!(SourceOffset::from_location(source, 4, 4).offset(), 10); - - // Out-of-range - assert_eq!( - SourceOffset::from_location(source, 5, 1).offset(), - source.len() - ); -} - -#[cfg(feature = "serde")] -#[test] -fn test_serialize_source_offset() { - use serde_json::json; - - assert_eq!(json!(SourceOffset::from(0)), 0) -} - -#[cfg(feature = "serde")] -#[test] -fn test_deserialize_source_offset() { - let offset: SourceOffset = serde_json::from_str("0").unwrap(); - assert_eq!(offset, SourceOffset::from(0)) -} |