1use crate::path::RelativePathBuf;
2
3use crate::{ConversionError, FmtHash, Line, LineSpan, Origin, Properties};
4
5use super::requirements::ReqId;
6
7#[derive(
10 Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
11)]
12#[serde(rename_all = "snake_case", deny_unknown_fields)]
13pub struct AnnotationSchema {
14 #[serde(serialize_with = "crate::serialize_schema_version")]
17 pub schema_version: Option<String>,
18 pub files: Vec<FileAnnotations>,
20 pub trace_properties: Option<Properties>,
25 pub origin: Option<Origin>,
28}
29
30#[derive(
33 Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
34)]
35#[serde(rename_all = "snake_case", deny_unknown_fields)]
36pub struct FileAnnotations {
37 #[schemars(with = "String")]
40 pub filepath: RelativePathBuf,
41 pub file_hash: FmtHash,
43 pub annotations: Annotations,
45 pub content: Option<String>,
47}
48
49#[derive(
51 Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
52)]
53#[serde(rename_all = "snake_case", deny_unknown_fields)]
54pub struct Annotations {
55 #[serde(default)]
57 pub traces: Vec<Trace>,
58 #[serde(default)]
61 pub elements: Vec<Element>,
62 #[serde(default)]
66 pub coverage_excludes: Vec<CoverageExclude>,
67}
68
69#[derive(
74 Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
75)]
76#[serde(deny_unknown_fields)]
77pub struct CoverageExclude {
78 pub kind: CoverageExcludeKind,
80 pub comment: String,
82}
83
84impl CoverageExclude {
85 pub fn start_line(&self) -> Line {
87 self.kind.start_line()
88 }
89}
90
91#[derive(
93 Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
94)]
95#[serde(rename_all = "snake_case", deny_unknown_fields)]
96pub enum CoverageExcludeKind {
97 Block { start: Line, end: Line },
100 Line(Line),
102}
103
104impl CoverageExcludeKind {
105 pub fn start_line(&self) -> Line {
107 match self {
108 CoverageExcludeKind::Block { start, end: _ } => *start,
109 CoverageExcludeKind::Line(line) => *line,
110 }
111 }
112}
113
114#[derive(
117 Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
118)]
119#[serde(rename_all = "snake_case", deny_unknown_fields)]
120pub struct Trace {
121 pub ids: Vec<ReqId>,
124 pub line: Line,
127 pub related_code: Option<TraceRelatedCodeVariant>,
130 pub kind: TraceKind,
133 pub properties: Option<Properties>,
136}
137
138impl std::fmt::Display for Trace {
139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140 write!(
141 f,
142 "Traces req({}) at line '{}'.",
143 self.ids
144 .iter()
145 .map(|id| id.to_string())
146 .collect::<Vec<String>>()
147 .join(","),
148 self.line
149 )?;
150
151 if let Some(code) = &self.related_code {
152 match code {
153 TraceRelatedCodeVariant::CodeBlock(code_block) => write!(
154 f,
155 " Related code block spans lines '{}..{}'.",
156 code_block.span.start, code_block.span.end
157 )?,
158 TraceRelatedCodeVariant::ElementAtLine(line) => {
159 write!(f, " Related element defined at line '{line}'.")?
160 }
161 }
162 }
163
164 Ok(())
165 }
166}
167
168#[derive(
171 Debug,
172 Clone,
173 Copy,
174 PartialEq,
175 Eq,
176 Hash,
177 serde::Serialize,
178 serde::Deserialize,
179 schemars::JsonSchema,
180)]
181#[serde(rename_all = "snake_case", deny_unknown_fields)]
182pub enum TraceKind {
183 Clarifies = 0,
185 Satisfies = 1,
187 Verifies = 2,
189 Links = 3,
191}
192
193impl TraceKind {
194 pub fn as_nr(&self) -> i32 {
195 *self as i32
196 }
197}
198
199impl TryFrom<i64> for TraceKind {
200 type Error = ConversionError;
201
202 fn try_from(value: i64) -> Result<Self, Self::Error> {
203 match value {
204 0 => Ok(TraceKind::Clarifies),
205 1 => Ok(TraceKind::Satisfies),
206 2 => Ok(TraceKind::Verifies),
207 3 => Ok(TraceKind::Links),
208 _ => Err(ConversionError::UnknownKind),
209 }
210 }
211}
212
213#[derive(
216 Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
217)]
218#[serde(untagged)]
219pub enum TraceRelatedCodeVariant {
220 CodeBlock(CodeBlock),
223 ElementAtLine(Line),
228}
229
230#[derive(
233 Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
234)]
235#[serde(rename_all = "snake_case", deny_unknown_fields)]
236pub struct CodeBlock {
237 pub kind: CodeBlockKind,
239 pub span: LineSpan,
242 pub content_hash: Option<FmtHash>,
244}
245
246#[derive(
248 Debug,
249 Clone,
250 Copy,
251 PartialEq,
252 Eq,
253 Hash,
254 serde::Serialize,
255 serde::Deserialize,
256 schemars::JsonSchema,
257)]
258#[serde(rename_all = "snake_case")]
259pub enum CodeBlockKind {
260 Other = 0,
261 If = 1,
262 ElseIf = 2,
263 Else = 3,
264 Loop = 4,
265 While = 5,
266 For = 6,
267 #[serde(alias = "switch", alias = "case")]
268 Match = 7,
269}
270
271impl CodeBlockKind {
272 pub fn as_nr(&self) -> i32 {
273 *self as i32
274 }
275}
276
277impl TryFrom<i64> for CodeBlockKind {
278 type Error = ConversionError;
279
280 fn try_from(value: i64) -> Result<Self, Self::Error> {
281 match value {
282 0 => Ok(CodeBlockKind::Other),
283 1 => Ok(CodeBlockKind::If),
284 2 => Ok(CodeBlockKind::ElseIf),
285 3 => Ok(CodeBlockKind::Else),
286 4 => Ok(CodeBlockKind::Loop),
287 5 => Ok(CodeBlockKind::While),
288 6 => Ok(CodeBlockKind::For),
289 7 => Ok(CodeBlockKind::Match),
290 _ => Err(ConversionError::UnknownKind),
291 }
292 }
293}
294
295#[derive(
299 Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
300)]
301#[serde(rename_all = "snake_case", deny_unknown_fields)]
302pub struct Element {
303 pub ident: Option<String>,
306 pub name: String,
310 pub definition_line: Line,
318 pub span: LineSpan,
321 pub kind: ElementKind,
324 pub content_hash: Option<FmtHash>,
326}
327
328impl std::fmt::Display for Element {
329 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
330 if self.kind == ElementKind::Test {
331 write!(f, "test: ")?;
332 }
333
334 write!(f, "`{}` @{}..{}", self.name, self.span.start, self.span.end)
335 }
336}
337
338#[derive(
341 Debug,
342 Clone,
343 Copy,
344 PartialEq,
345 Eq,
346 Hash,
347 serde::Serialize,
348 serde::Deserialize,
349 schemars::JsonSchema,
350)]
351#[serde(rename_all = "snake_case")]
352pub enum ElementKind {
353 Other = 0,
355 #[serde(alias = "test_case")]
357 Test = 1,
358 #[serde(alias = "mod", alias = "package")]
360 Module = 2,
361 #[serde(alias = "fn", alias = "method")]
363 Function = 3,
364 #[serde(alias = "var", alias = "static")]
366 Variable = 4,
367 Const = 5,
369 #[serde(alias = "struct", alias = "enum", alias = "class", alias = "union")]
371 Type = 6,
372 #[serde(alias = "property")]
374 Field = 7,
375 #[serde(alias = "interface", alias = "abstract_type")]
377 Trait = 8,
378 #[serde(alias = "virtual_function")]
380 FunctionSignature = 9,
381}
382
383impl ElementKind {
384 pub fn as_nr(&self) -> i32 {
385 *self as i32
386 }
387}
388
389impl TryFrom<i64> for ElementKind {
390 type Error = ConversionError;
391
392 fn try_from(value: i64) -> Result<Self, Self::Error> {
393 match value {
394 0 => Ok(ElementKind::Other),
395 1 => Ok(ElementKind::Test),
396 2 => Ok(ElementKind::Module),
397 3 => Ok(ElementKind::Function),
398 4 => Ok(ElementKind::Variable),
399 5 => Ok(ElementKind::Const),
400 6 => Ok(ElementKind::Type),
401 7 => Ok(ElementKind::Field),
402 8 => Ok(ElementKind::Trait),
403 _ => Err(ConversionError::UnknownKind),
404 }
405 }
406}