1use alloc::borrow::Cow;
7use core::{fmt, ops::Range};
8
9#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct Message {
16 pub span: Option<Range<usize>>,
18 pub reason: Cow<'static, str>,
20 pub rule_id: &'static str,
22 pub source: &'static str,
24}
25
26impl fmt::Display for Message {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 if let Some(span) = &self.span {
29 write!(f, "{}..{}: ", span.start, span.end)?;
30 }
31 write!(f, "{} ({}:{})", self.reason, self.source, self.rule_id)
32 }
33}
34
35#[cfg(test)]
36mod tests {
37 use super::Message;
38 use alloc::{borrow::Cow, format, string::ToString};
39 use core::fmt::Write as _;
40
41 struct FailingWriter;
42
43 impl core::fmt::Write for FailingWriter {
44 fn write_str(&mut self, _value: &str) -> core::fmt::Result {
45 Err(core::fmt::Error)
46 }
47 }
48
49 #[test]
50 fn diagnostics_borrow_static_reasons_and_display_byte_ranges() {
51 let mut message = Message {
52 span: None,
53 reason: "invalid value".into(),
54 rule_id: "example",
55 source: "parser",
56 };
57 assert_eq!(message.reason, Cow::Borrowed("invalid value"));
58 assert_eq!(message.to_string(), "invalid value (parser:example)");
59 assert!(write!(&mut FailingWriter, "{message}").is_err());
60
61 message.span = Some(2..5);
62 message.reason = format!("invalid value {}", 42).into();
63 assert_eq!(
64 message.to_string(),
65 "2..5: invalid value 42 (parser:example)"
66 );
67 assert!(write!(&mut FailingWriter, "{message}").is_err());
68 }
69}