use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::fmt::Display;
use core::ops::Range;
#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum Severity {
Help,
Note,
Warning,
Error,
Bug,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum LabelStyle {
Primary,
Secondary,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Label<FileId> {
pub style: LabelStyle,
pub file_id: FileId,
pub range: Range<usize>,
pub message: String,
}
impl<FileId> Label<FileId> {
pub fn new(
style: LabelStyle,
file_id: FileId,
range: impl Into<Range<usize>>,
) -> Label<FileId> {
Label {
style,
file_id,
range: range.into(),
message: String::new(),
}
}
pub fn primary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> {
Label::new(LabelStyle::Primary, file_id, range)
}
pub fn secondary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> {
Label::new(LabelStyle::Secondary, file_id, range)
}
#[must_use]
pub fn with_message(mut self, message: impl Display) -> Label<FileId> {
self.message = message.to_string();
self
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Diagnostic<FileId> {
pub severity: Severity,
pub code: Option<String>,
pub message: String,
pub labels: Vec<Label<FileId>>,
pub notes: Vec<String>,
}
impl<FileId> Diagnostic<FileId> {
pub fn new(severity: Severity) -> Diagnostic<FileId> {
Diagnostic {
severity,
code: None,
message: String::new(),
labels: Vec::new(),
notes: Vec::new(),
}
}
#[must_use]
pub fn bug() -> Diagnostic<FileId> {
Diagnostic::new(Severity::Bug)
}
#[must_use]
pub fn error() -> Diagnostic<FileId> {
Diagnostic::new(Severity::Error)
}
#[must_use]
pub fn warning() -> Diagnostic<FileId> {
Diagnostic::new(Severity::Warning)
}
#[must_use]
pub fn note() -> Diagnostic<FileId> {
Diagnostic::new(Severity::Note)
}
#[must_use]
pub fn help() -> Diagnostic<FileId> {
Diagnostic::new(Severity::Help)
}
#[must_use]
pub fn with_code(mut self, code: impl Display) -> Diagnostic<FileId> {
self.code = Some(code.to_string());
self
}
#[must_use]
pub fn with_message(mut self, message: impl Display) -> Diagnostic<FileId> {
self.message = message.to_string();
self
}
#[must_use]
pub fn with_label(mut self, label: Label<FileId>) -> Diagnostic<FileId> {
self.labels.push(label);
self
}
#[must_use]
pub fn with_labels(mut self, mut labels: Vec<Label<FileId>>) -> Diagnostic<FileId> {
self.labels.append(&mut labels);
self
}
#[must_use]
pub fn with_labels_iter(
mut self,
labels: impl IntoIterator<Item = Label<FileId>>,
) -> Diagnostic<FileId> {
self.labels.extend(labels);
self
}
#[allow(clippy::needless_pass_by_value)]
#[must_use]
pub fn with_note(mut self, note: impl ToString) -> Diagnostic<FileId> {
self.notes.push(note.to_string());
self
}
#[must_use]
pub fn with_notes(mut self, mut notes: Vec<String>) -> Diagnostic<FileId> {
self.notes.append(&mut notes);
self
}
#[must_use]
pub fn with_notes_iter(
mut self,
notes: impl IntoIterator<Item = String>,
) -> Diagnostic<FileId> {
self.notes.extend(notes);
self
}
}