use crate::path::RelativePathBuf;
use crate::{ConversionError, FmtHash, Line, LineSpan, Origin, Properties};
use super::requirements::ReqId;
#[derive(
Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct AnnotationSchema {
#[serde(serialize_with = "crate::serialize_schema_version")]
pub schema_version: Option<String>,
pub files: Vec<FileAnnotations>,
pub trace_properties: Option<Properties>,
pub origin: Option<Origin>,
}
#[derive(
Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct FileAnnotations {
#[schemars(with = "String")]
pub filepath: RelativePathBuf,
pub file_hash: FmtHash,
pub annotations: Annotations,
pub content: Option<String>,
}
#[derive(
Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct Annotations {
#[serde(default)]
pub traces: Vec<Trace>,
#[serde(default)]
pub elements: Vec<Element>,
#[serde(default)]
pub coverage_excludes: Vec<CoverageExclude>,
}
#[derive(
Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
)]
#[serde(deny_unknown_fields)]
pub struct CoverageExclude {
pub kind: CoverageExcludeKind,
pub comment: String,
}
impl CoverageExclude {
pub fn start_line(&self) -> Line {
self.kind.start_line()
}
}
#[derive(
Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum CoverageExcludeKind {
Block { start: Line, end: Line },
Line(Line),
}
impl CoverageExcludeKind {
pub fn start_line(&self) -> Line {
match self {
CoverageExcludeKind::Block { start, end: _ } => *start,
CoverageExcludeKind::Line(line) => *line,
}
}
}
#[derive(
Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct Trace {
pub ids: Vec<ReqId>,
pub line: Line,
pub related_code: Option<TraceRelatedCodeVariant>,
pub kind: TraceKind,
pub properties: Option<Properties>,
}
impl std::fmt::Display for Trace {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Traces req({}) at line '{}'.",
self.ids
.iter()
.map(|id| id.to_string())
.collect::<Vec<String>>()
.join(","),
self.line
)?;
if let Some(code) = &self.related_code {
match code {
TraceRelatedCodeVariant::CodeBlock(code_block) => write!(
f,
" Related code block spans lines '{}..{}'.",
code_block.span.start, code_block.span.end
)?,
TraceRelatedCodeVariant::ElementAtLine(line) => {
write!(f, " Related element defined at line '{line}'.")?
}
}
}
Ok(())
}
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
serde::Serialize,
serde::Deserialize,
schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum TraceKind {
Clarifies = 0,
Satisfies = 1,
Verifies = 2,
Links = 3,
}
impl TraceKind {
pub fn as_nr(&self) -> i32 {
*self as i32
}
}
impl TryFrom<i64> for TraceKind {
type Error = ConversionError;
fn try_from(value: i64) -> Result<Self, Self::Error> {
match value {
0 => Ok(TraceKind::Clarifies),
1 => Ok(TraceKind::Satisfies),
2 => Ok(TraceKind::Verifies),
3 => Ok(TraceKind::Links),
_ => Err(ConversionError::UnknownKind),
}
}
}
#[derive(
Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
)]
#[serde(untagged)]
pub enum TraceRelatedCodeVariant {
CodeBlock(CodeBlock),
ElementAtLine(Line),
}
#[derive(
Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct CodeBlock {
pub kind: CodeBlockKind,
pub span: LineSpan,
pub content_hash: Option<FmtHash>,
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
serde::Serialize,
serde::Deserialize,
schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum CodeBlockKind {
Other = 0,
If = 1,
ElseIf = 2,
Else = 3,
Loop = 4,
While = 5,
For = 6,
#[serde(alias = "switch", alias = "case")]
Match = 7,
}
impl CodeBlockKind {
pub fn as_nr(&self) -> i32 {
*self as i32
}
}
impl TryFrom<i64> for CodeBlockKind {
type Error = ConversionError;
fn try_from(value: i64) -> Result<Self, Self::Error> {
match value {
0 => Ok(CodeBlockKind::Other),
1 => Ok(CodeBlockKind::If),
2 => Ok(CodeBlockKind::ElseIf),
3 => Ok(CodeBlockKind::Else),
4 => Ok(CodeBlockKind::Loop),
5 => Ok(CodeBlockKind::While),
6 => Ok(CodeBlockKind::For),
7 => Ok(CodeBlockKind::Match),
_ => Err(ConversionError::UnknownKind),
}
}
}
#[derive(
Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct Element {
pub ident: Option<String>,
pub name: String,
pub definition_line: Line,
pub span: LineSpan,
pub kind: ElementKind,
pub content_hash: Option<FmtHash>,
}
impl std::fmt::Display for Element {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.kind == ElementKind::Test {
write!(f, "test: ")?;
}
write!(f, "`{}` @{}..{}", self.name, self.span.start, self.span.end)
}
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
serde::Serialize,
serde::Deserialize,
schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum ElementKind {
Other = 0,
#[serde(alias = "test_case")]
Test = 1,
#[serde(alias = "mod", alias = "package")]
Module = 2,
#[serde(alias = "fn", alias = "method")]
Function = 3,
#[serde(alias = "var", alias = "static")]
Variable = 4,
Const = 5,
#[serde(alias = "struct", alias = "enum", alias = "class", alias = "union")]
Type = 6,
#[serde(alias = "property")]
Field = 7,
#[serde(alias = "interface", alias = "abstract_type")]
Trait = 8,
#[serde(alias = "virtual_function")]
FunctionSignature = 9,
}
impl ElementKind {
pub fn as_nr(&self) -> i32 {
*self as i32
}
}
impl TryFrom<i64> for ElementKind {
type Error = ConversionError;
fn try_from(value: i64) -> Result<Self, Self::Error> {
match value {
0 => Ok(ElementKind::Other),
1 => Ok(ElementKind::Test),
2 => Ok(ElementKind::Module),
3 => Ok(ElementKind::Function),
4 => Ok(ElementKind::Variable),
5 => Ok(ElementKind::Const),
6 => Ok(ElementKind::Type),
7 => Ok(ElementKind::Field),
8 => Ok(ElementKind::Trait),
_ => Err(ConversionError::UnknownKind),
}
}
}