tiger_lib/report/report_struct.rs
1use serde::Serialize;
2use strum_macros::{Display, EnumIter, EnumString, IntoStaticStr};
3
4use crate::report::ErrorKey;
5use crate::token::Loc;
6
7/// Describes a report about a potentially problematic situation that can be logged.
8#[derive(Debug, Clone, Hash, PartialEq, Eq)]
9pub struct LogReport {
10 /// Used for choosing output colors and for filtering reports.
11 pub severity: Severity,
12 /// Mostly used for filtering reports.
13 pub confidence: Confidence,
14 /// Defines the problem category. Used for filtering reports.
15 pub key: ErrorKey,
16 /// The primary error message. A short description of the problem.
17 pub msg: String,
18 /// Optional info message to be printed at the end.
19 pub info: Option<String>,
20 /// Should contain one or more elements.
21 pub pointers: Vec<PointedMessage>,
22}
23
24impl LogReport {
25 /// Returns the primary pointer.
26 ///
27 /// # Panics
28 /// May panic if this is an invalid `LogReport` with no pointers.
29 pub fn primary(&self) -> &PointedMessage {
30 self.pointers.first().expect("A LogReport must always have at least one PointedMessage.")
31 }
32
33 /// Returns the length of the longest line number.
34 pub fn indentation(&self) -> usize {
35 self.pointers.iter().map(|pointer| pointer.loc.line.to_string().len()).max().unwrap_or(0)
36 }
37}
38
39#[derive(Debug, Clone, Hash, PartialEq, Eq)]
40pub struct PointedMessage {
41 /// Which file and where in the file the error occurs.
42 /// Might point to a whole file, rather than a specific location in the file.
43 pub loc: Loc,
44 /// The length of the offending phrase in characters.
45 /// Set this to 0 if the length cannot be determined.
46 /// This will determine the number of carets that are printed at the given location.
47 /// e.g.: ^^^^^^^^^
48 /// TODO: If we end up adding length to Loc, this field can be deleted.
49 pub length: usize,
50 /// A short message that will be printed at the caret location.
51 pub msg: Option<String>,
52}
53
54impl PointedMessage {
55 pub fn new(loc: Loc) -> Self {
56 Self { loc, msg: None, length: 0 }
57 }
58}
59
60/// Determines the output colour.
61/// User can also filter by minimum severity level: e.g. don't show me Info-level messages.
62///
63/// The order of these enum values determines the level of severity they denote.
64/// Do not change the order unless you mean to change the logic of the program!
65#[derive(
66 Default,
67 Debug,
68 Display,
69 Clone,
70 Copy,
71 Ord,
72 PartialOrd,
73 Eq,
74 PartialEq,
75 Hash,
76 IntoStaticStr,
77 EnumString,
78 EnumIter,
79 Serialize,
80)]
81#[serde(rename_all = "kebab-case")]
82#[strum(serialize_all = "kebab-case")]
83pub enum Severity {
84 /// These are things that aren't necessarily wrong, but there may be a better, more
85 /// idiomatic way to do it. This may also include performance issues.
86 Tips,
87 /// This code smells.
88 /// The player is unlikely to be impacted directly, but developers working on this codebase
89 /// will likely experience maintenance headaches.
90 Untidy,
91 /// This will result in glitches that will noticeably impact the player's gaming experience.
92 /// Missing translations are an example.
93 #[default]
94 Warning,
95 /// This code probably doesn't work as intended. The player may experience bugs.
96 Error,
97 /// This is likely to cause crashes.
98 Fatal,
99}
100
101impl Severity {
102 /// Reduce the severity to at most `max_sev`, unless severity is `Fatal`, then stays `Fatal`.
103 #[must_use]
104 pub fn at_most(self, max_sev: Severity) -> Severity {
105 if self == Severity::Fatal {
106 Severity::Fatal
107 } else {
108 self.min(max_sev)
109 }
110 }
111}
112
113/// Mostly invisible in the output.
114/// User can filter by minimum confidence level.
115/// This would be a dial for how many false positives they're willing to put up with.
116///
117/// The order of these enum values determines the level of confidence they denote.
118/// Do not change the order unless you mean to change the logic of the program!
119#[derive(
120 Default,
121 Debug,
122 Clone,
123 Copy,
124 Ord,
125 PartialOrd,
126 Eq,
127 PartialEq,
128 Hash,
129 IntoStaticStr,
130 EnumIter,
131 EnumString,
132 Serialize,
133)]
134#[serde(rename_all = "kebab-case")]
135#[strum(serialize_all = "kebab-case")]
136pub enum Confidence {
137 /// Quite likely to be a false positive.
138 Weak,
139 /// Reasonably confident that the problem is real.
140 #[default]
141 Reasonable,
142 /// Very confident that this problem is real.
143 Strong,
144}