1#![allow(clippy::needless_update)]
2
3use std::borrow::Cow;
4
5pub trait Report: Send + Sync {
6 fn report(&self, msg: Message<'_>) -> Result<(), std::io::Error>;
7
8 fn generate_final_result(&self) -> Result<(), std::io::Error> {
9 Ok(())
10 }
11}
12
13#[derive(Clone, Debug, serde::Serialize, derive_more::From)]
14#[serde(rename_all = "snake_case")]
15#[serde(tag = "type")]
16#[non_exhaustive]
17pub enum Message<'m> {
18 BinaryFile(BinaryFile<'m>),
19 Typo(Typo<'m>),
20 FileType(FileType<'m>),
21 File(File<'m>),
22 Parse(Parse<'m>),
23 Error(Error<'m>),
24}
25
26impl<'m> Message<'m> {
27 pub fn is_typo(&self) -> bool {
28 match self {
29 Message::BinaryFile(_) => false,
30 Message::Typo(c) => !c.corrections.is_valid(),
31 Message::FileType(_) => false,
32 Message::File(_) => false,
33 Message::Parse(_) => false,
34 Message::Error(_) => false,
35 }
36 }
37
38 pub fn is_error(&self) -> bool {
39 match self {
40 Message::BinaryFile(_) => false,
41 Message::Typo(_) => false,
42 Message::FileType(_) => false,
43 Message::File(_) => false,
44 Message::Parse(_) => false,
45 Message::Error(_) => true,
46 }
47 }
48
49 pub fn context(self, context: Option<Context<'m>>) -> Self {
50 match self {
51 Message::Typo(typo) => {
52 let typo = typo.context(context);
53 Message::Typo(typo)
54 }
55 Message::Parse(parse) => {
56 let parse = parse.context(context);
57 Message::Parse(parse)
58 }
59 Message::Error(error) => {
60 let error = error.context(context);
61 Message::Error(error)
62 }
63 _ => self,
64 }
65 }
66}
67
68#[derive(Clone, Debug, serde::Serialize, derive_more::Display, derive_setters::Setters)]
69#[display("Skipping binary file {}", path.display())]
70#[non_exhaustive]
71pub struct BinaryFile<'m> {
72 pub path: &'m std::path::Path,
73}
74
75#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
76#[non_exhaustive]
77pub struct Typo<'m> {
78 #[serde(flatten)]
79 pub context: Option<Context<'m>>,
80 #[serde(skip)]
81 pub buffer: Cow<'m, [u8]>,
82 pub byte_offset: usize,
83 pub typo: &'m str,
84 pub corrections: typos::Status<'m>,
85}
86
87impl Default for Typo<'_> {
88 fn default() -> Self {
89 Self {
90 context: None,
91 buffer: Cow::Borrowed(&[]),
92 byte_offset: 0,
93 typo: "",
94 corrections: typos::Status::Invalid,
95 }
96 }
97}
98
99#[derive(Clone, Debug, serde::Serialize, derive_more::From)]
100#[serde(untagged)]
101#[non_exhaustive]
102pub enum Context<'m> {
103 File(FileContext<'m>),
104 Path(PathContext<'m>),
105}
106
107impl std::fmt::Display for Context<'_> {
108 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
109 match self {
110 Context::File(c) => write!(f, "{}:{}", c.path.display(), c.line_num),
111 Context::Path(c) => write!(f, "{}", c.path.display()),
112 }
113 }
114}
115
116#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
117#[non_exhaustive]
118pub struct FileContext<'m> {
119 pub path: &'m std::path::Path,
120 pub line_num: usize,
121}
122
123impl Default for FileContext<'_> {
124 fn default() -> Self {
125 Self {
126 path: std::path::Path::new("-"),
127 line_num: 0,
128 }
129 }
130}
131
132#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
133#[non_exhaustive]
134pub struct PathContext<'m> {
135 pub path: &'m std::path::Path,
136}
137
138impl Default for PathContext<'_> {
139 fn default() -> Self {
140 Self {
141 path: std::path::Path::new("-"),
142 }
143 }
144}
145
146#[derive(Copy, Clone, Debug, serde::Serialize)]
147#[serde(rename_all = "snake_case")]
148#[non_exhaustive]
149pub enum ParseKind {
150 Identifier,
151 Word,
152}
153
154#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
155#[non_exhaustive]
156pub struct FileType<'m> {
157 pub path: &'m std::path::Path,
158 pub file_type: Option<&'m str>,
159}
160
161impl<'m> FileType<'m> {
162 pub fn new(path: &'m std::path::Path, file_type: Option<&'m str>) -> Self {
163 Self { path, file_type }
164 }
165}
166
167impl Default for FileType<'_> {
168 fn default() -> Self {
169 Self {
170 path: std::path::Path::new("-"),
171 file_type: None,
172 }
173 }
174}
175
176#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
177#[non_exhaustive]
178pub struct File<'m> {
179 pub path: &'m std::path::Path,
180}
181
182impl<'m> File<'m> {
183 pub fn new(path: &'m std::path::Path) -> Self {
184 Self { path }
185 }
186}
187
188impl Default for File<'_> {
189 fn default() -> Self {
190 Self {
191 path: std::path::Path::new("-"),
192 }
193 }
194}
195
196#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
197#[non_exhaustive]
198pub struct Parse<'m> {
199 #[serde(flatten)]
200 pub context: Option<Context<'m>>,
201 pub kind: ParseKind,
202 pub data: &'m str,
203}
204
205impl Default for Parse<'_> {
206 fn default() -> Self {
207 Self {
208 context: None,
209 kind: ParseKind::Identifier,
210 data: "",
211 }
212 }
213}
214
215#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
216#[non_exhaustive]
217pub struct Error<'m> {
218 #[serde(flatten)]
219 pub context: Option<Context<'m>>,
220 pub msg: String,
221}
222
223impl Error<'_> {
224 pub fn new(msg: String) -> Self {
225 Self { context: None, msg }
226 }
227}
228
229impl Default for Error<'_> {
230 fn default() -> Self {
231 Self {
232 context: None,
233 msg: "".to_owned(),
234 }
235 }
236}