🪄 Srcerr

Crates.io CI Coverage Status

Types to track error codes and details.

This library provies a [SourceError] struct that holds:

This library backs onto [codespan-reporting] to render diagnostic errors.

The "codespan" feature can also be used to expose [codespan] types:

toml srcerr = { version = "0.3.0", features = ["codespan"] }

Usage

1. Implement ErrorCode

```rust

[derive(Clone, Copy, Debug, PartialEq, Eq)]

pub enum SimpleErrorCode { /// Error when a value is out of range. ValueOutOfRange, /// Error when a string is too long. StringTooLong, }

impl ErrorCode for SimpleErrorCode { const ERRORCODEMAX: usize = 2; const PREFIX: &'static str = "E";

fn code(self) -> usize {
    match self {
        Self::ValueOutOfRange => 1,
        Self::StringTooLong => 2,
    }
}

fn description(self) -> &'static str {
    match self {
        Self::ValueOutOfRange => "Value out of range.",
        Self::StringTooLong => "String provided is too long.",
    }
}

} ```

2. Implement ErrorDetail

```rust

[derive(Debug)]

pub enum SimpleErrorDetail { /// Error when a value is out of range. ValueOutOfRange { /// ID of the file containing the invalid value. fileid: usize, /// The value. value: i32, /// Byte begin and end indices where the value is defined. valuebyteindices: Range, /// Range that the value must be within. range: RangeInclusive, }, /// Error when a string is too long. StringTooLong { /// ID of the file containing the invalid value. fileid: usize, /// The value that is too long. value: String, /// Byte begin and end indices where the value is defined. valuebyteindices: Range, /// Maximum length allowed for the string. limit: usize, }, }

impl<'files> ErrorDetail<'files> for SimpleErrorDetail { type Files = SimpleFiles<&'files str, &'files str>;

fn labels(&self) -> Vec<Label<usize>> {
    match self {
        Self::ValueOutOfRange {
            file_id,
            value_byte_indices,
            range,
            ..
        } => {
            vec![
                Label::primary(*file_id, value_byte_indices.clone()).with_message(format!(
                    "not within the range: `{}..={}`",
                    range.start(),
                    range.end()
                )),
            ]
        }
        Self::StringTooLong {
            file_id,
            value_byte_indices,
            limit,
            ..
        } => {
            vec![
                Label::primary(*file_id, value_byte_indices.clone())
                    .with_message(format!("exceeds the {} character limit.", limit)),
            ]
        }
    }
}

fn notes(&self, _files: &Self::Files) -> Vec<String> {
    match self {
        Self::ValueOutOfRange { range, .. } => {
            let valid_exprs = range.clone().map(|n| Cow::Owned(n.to_string()));
            let suggestion = Note::valid_exprs(valid_exprs).expect("Failed to format note.");
            vec![suggestion]
        }
        Self::StringTooLong { .. } => vec![],
    }
}

} ```

3. Construct SourceError when there is an error.

```rust fn valueoutofrange<'f>( fileid: usize, ) -> SourceError<'f, SimpleErrorCode, SimpleErrorDetail, SimpleFiles<&'f str, &'f str>> { let errorcode = SimpleErrorCode::ValueOutOfRange; let errordetail = SimpleErrorDetail::ValueOutOfRange { fileid, value: -1, valuebyte_indices: 21..23, range: 1..=3, }; let severity = Severity::Error;

SourceError::new(error_code, error_detail, severity)

}

fn stringtoolong<'f>( fileid: usize, content: &str, ) -> SourceError<'f, SimpleErrorCode, SimpleErrorDetail, SimpleFiles<&'f str, &'f str>> { let errorcode = SimpleErrorCode::StringTooLong; let errordetail = SimpleErrorDetail::StringTooLong { fileid, value: content[40..47].tostring(), valuebyte_indices: 39..48, limit: 5, }; let severity = Severity::Error;

SourceError::new(error_code, error_detail, severity)

} ```

4. Output the diagnostic message.

```rust let valueoutofrange = valueoutofrange(fileid); let valueoutofrange = valueoutofrange.asdiagnostic(&files); let stringtoolong = stringtoolong(fileid, content); let stringtoolong = stringtoolong.asdiagnostic(&files);

let writer = StandardStream::stderr(ColorChoice::Always); let config = term::Config::default(); term::emit(&mut writer.lock(), &config, &files, &valueoutofrange)?; term::emit(&mut writer.lock(), &config, &files, &stringtoo_long)?; ```

Sample usage can be seen in the examples.

cargo run --example simple cargo run --example source_ref_hint cargo run --example long_expr_context cargo run --example html > /tmp/index.html cargo run --example codespan --features codespan

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.