Skip to main content

mantra_schema/
lib.rs

1use serde::Serializer;
2use sha2::Digest;
3
4pub mod annotations;
5mod encoding;
6pub mod product;
7pub mod report;
8pub mod requirements;
9pub mod reviews;
10pub mod test_runs;
11
12pub use relative_path as path;
13pub use time;
14
15/// The version of the schema that is defined in this crate.
16/// [req("exchange.versioned")]
17pub const SCHEMA_VERSION: &str = env!("CARGO_PKG_VERSION");
18
19pub const PRODUCTS_FOLDER_NAME: &str = "products";
20pub const REQUIREMENTS_FOLDER_NAME: &str = "requirements";
21pub const REVIEWS_FOLDER_NAME: &str = "reviews";
22pub const TEST_RUNS_FOLDER_NAME: &str = "test-runs";
23pub const SOURCES_FOLDER_NAME: &str = "sources";
24
25/// Represents a line in a text file.
26/// Line numbers start at 1 in *mantra*.
27pub type Line = i64;
28pub type Origin = serde_json::Value;
29pub type Properties = serde_json::value::Map<String, serde_json::Value>;
30
31#[derive(
32    Debug,
33    Clone,
34    Copy,
35    PartialEq,
36    Eq,
37    Hash,
38    serde::Serialize,
39    serde::Deserialize,
40    schemars::JsonSchema,
41)]
42#[serde(deny_unknown_fields)]
43pub struct LineSpan {
44    pub start: Line,
45    pub end: Line,
46}
47
48fn serialize_schema_version<S>(_value: &Option<String>, ser: S) -> Result<S::Ok, S::Error>
49where
50    S: Serializer,
51{
52    ser.serialize_str(SCHEMA_VERSION)
53}
54
55#[derive(
56    Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
57)]
58#[serde(deny_unknown_fields)]
59pub struct Revision {
60    pub nr: i64,
61    pub authors: Vec<String>,
62    pub comment: String,
63}
64
65#[derive(
66    Debug,
67    Clone,
68    PartialEq,
69    Eq,
70    Hash,
71    sqlx::Type,
72    serde::Serialize,
73    serde::Deserialize,
74    schemars::JsonSchema,
75)]
76// #[cfg_attr(feature = "sqlx", derive(sqlx_macros::Encode, sqlx_macros::Type))]
77#[sqlx(transparent)]
78#[serde(transparent)]
79pub struct FmtHash(String);
80
81impl FmtHash {
82    pub fn hash(&self) -> &str {
83        &self.0
84    }
85
86    pub fn new(s: &str) -> Self {
87        let mut hash = sha2::Sha256::new();
88        hash.update(s.as_bytes());
89        Self(base16ct::lower::encode_string(&hash.finalize()))
90    }
91
92    pub fn with_inner(hash: String) -> Self {
93        Self(hash)
94    }
95}
96
97impl std::fmt::Display for FmtHash {
98    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99        write!(f, "{}", self.0)
100    }
101}
102
103impl<S: serde::Serialize> From<&S> for FmtHash {
104    fn from(value: &S) -> Self {
105        let content = serde_json::to_string(value).expect(
106            "Types that implement serde::Serialize should never fail to serialize to JSON.",
107        );
108        Self::new(&content)
109    }
110}
111
112impl std::str::FromStr for FmtHash {
113    type Err = ();
114
115    fn from_str(s: &str) -> Result<Self, Self::Err> {
116        Ok(Self::new(s))
117    }
118}
119
120#[derive(Debug, thiserror::Error)]
121pub enum ConversionError {
122    #[error("Number does not match to a known kind.")]
123    UnknownKind,
124    #[error("Number does not match to a known state.")]
125    UnknownState,
126    #[error("Given format is unknown")]
127    UnknownFormat,
128}
129
130#[derive(Debug, thiserror::Error)]
131pub enum IdentError {
132    #[error("Given ID contains invalid characters.")]
133    InvalidCharacter,
134}