Skip to main content

tokmd_envelope/
artifact.rs

1//! Artifact references attached to sensor reports.
2
3use serde::{Deserialize, Serialize};
4
5/// Artifact reference in the sensor report.
6///
7/// # Examples
8///
9/// ```
10/// use tokmd_envelope::Artifact;
11///
12/// let art = Artifact::receipt("output/receipt.json")
13///     .with_id("analysis")
14///     .with_mime("application/json");
15/// assert_eq!(art.artifact_type, "receipt");
16/// assert_eq!(art.id.as_deref(), Some("analysis"));
17/// ```
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct Artifact {
20    /// Artifact identifier (e.g., "analysis", "handoff").
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub id: Option<String>,
23    /// Artifact type (e.g., "comment", "receipt", "badge").
24    #[serde(rename = "type")]
25    pub artifact_type: String,
26    /// Path to the artifact file.
27    pub path: String,
28    /// MIME type (e.g., "application/json").
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub mime: Option<String>,
31}
32
33impl Artifact {
34    /// Create a new artifact reference.
35    pub fn new(artifact_type: impl Into<String>, path: impl Into<String>) -> Self {
36        Self {
37            id: None,
38            artifact_type: artifact_type.into(),
39            path: path.into(),
40            mime: None,
41        }
42    }
43
44    /// Create a comment artifact.
45    pub fn comment(path: impl Into<String>) -> Self {
46        Self::new("comment", path)
47    }
48
49    /// Create a receipt artifact.
50    pub fn receipt(path: impl Into<String>) -> Self {
51        Self::new("receipt", path)
52    }
53
54    /// Create a badge artifact.
55    pub fn badge(path: impl Into<String>) -> Self {
56        Self::new("badge", path)
57    }
58
59    /// Set the artifact ID. Builder pattern.
60    pub fn with_id(mut self, id: impl Into<String>) -> Self {
61        self.id = Some(id.into());
62        self
63    }
64
65    /// Set the MIME type. Builder pattern.
66    pub fn with_mime(mut self, mime: impl Into<String>) -> Self {
67        self.mime = Some(mime.into());
68        self
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::Artifact;
75
76    #[test]
77    fn artifact_builders_cover_variants() {
78        let custom = Artifact::new("custom", "out/custom.json");
79        assert_eq!(custom.artifact_type, "custom");
80        assert_eq!(custom.path, "out/custom.json");
81
82        let comment = Artifact::comment("out/comment.md");
83        assert_eq!(comment.artifact_type, "comment");
84        assert_eq!(comment.path, "out/comment.md");
85
86        let receipt = Artifact::receipt("out/receipt.json")
87            .with_id("receipt")
88            .with_mime("application/json");
89        assert_eq!(receipt.artifact_type, "receipt");
90        assert_eq!(receipt.path, "out/receipt.json");
91        assert_eq!(receipt.id.as_deref(), Some("receipt"));
92        assert_eq!(receipt.mime.as_deref(), Some("application/json"));
93
94        let badge = Artifact::badge("out/badge.svg");
95        assert_eq!(badge.artifact_type, "badge");
96        assert_eq!(badge.path, "out/badge.svg");
97    }
98}