use alloc::boxed::Box;
use alloc::vec::Vec;
use crate::{Label, Severity};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Diagnostic {
severity: Severity,
message: Box<str>,
primary: Label,
secondary: Vec<Label>,
notes: Vec<Box<str>>,
help: Vec<Box<str>>,
}
impl Diagnostic {
#[inline]
#[must_use]
pub fn new(severity: Severity, message: impl Into<Box<str>>, primary: Label) -> Self {
Self {
severity,
message: message.into(),
primary,
secondary: Vec::new(),
notes: Vec::new(),
help: Vec::new(),
}
}
#[must_use]
pub fn with_secondary(mut self, label: Label) -> Self {
self.secondary.push(label);
self
}
#[must_use]
pub fn with_note(mut self, note: impl Into<Box<str>>) -> Self {
self.notes.push(note.into());
self
}
#[must_use]
pub fn with_help(mut self, help: impl Into<Box<str>>) -> Self {
self.help.push(help.into());
self
}
#[inline]
#[must_use]
pub const fn severity(&self) -> Severity {
self.severity
}
#[inline]
#[must_use]
pub fn message(&self) -> &str {
&self.message
}
#[inline]
#[must_use]
pub const fn primary(&self) -> &Label {
&self.primary
}
#[inline]
#[must_use]
pub fn secondary(&self) -> &[Label] {
&self.secondary
}
pub fn notes(&self) -> impl ExactSizeIterator<Item = &str> {
self.notes.iter().map(AsRef::as_ref)
}
pub fn help(&self) -> impl ExactSizeIterator<Item = &str> {
self.help.iter().map(AsRef::as_ref)
}
}
#[cfg(test)]
mod tests {
use span_lang::Span;
use super::*;
#[test]
fn test_new_starts_with_empty_extras() {
let diag = Diagnostic::new(
Severity::Error,
"type mismatch",
Label::new(Span::new(8, 11), "here"),
);
assert_eq!(diag.severity(), Severity::Error);
assert_eq!(diag.message(), "type mismatch");
assert_eq!(diag.primary().span(), Span::new(8, 11));
assert!(diag.secondary().is_empty());
assert_eq!(diag.notes().count(), 0);
assert_eq!(diag.help().count(), 0);
}
#[test]
fn test_builders_accumulate_in_order() {
let diag = Diagnostic::new(Severity::Error, "m", Label::unlabelled(Span::empty(0)))
.with_secondary(Label::new(Span::new(1, 2), "a"))
.with_secondary(Label::new(Span::new(3, 4), "b"))
.with_note("n1")
.with_note("n2")
.with_help("h1");
let secondary: Vec<_> = diag.secondary().iter().map(Label::message).collect();
assert_eq!(secondary, ["a", "b"]);
assert_eq!(diag.notes().collect::<Vec<_>>(), ["n1", "n2"]);
assert_eq!(diag.help().collect::<Vec<_>>(), ["h1"]);
}
}