wfe_core/models/
artifact.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10pub struct ArtifactRef {
11 pub digest: String,
13}
14
15impl ArtifactRef {
16 pub fn new(digest: impl Into<String>) -> Self {
18 Self {
19 digest: digest.into(),
20 }
21 }
22
23 pub fn algorithm(&self) -> Option<&str> {
25 self.digest.split_once(':').map(|(algo, _)| algo)
26 }
27
28 pub fn hash(&self) -> Option<&str> {
30 self.digest.split_once(':').map(|(_, hash)| hash)
31 }
32}
33
34#[derive(Debug, Clone)]
39pub struct ArtifactBlob {
40 pub digest: String,
42 pub size: u64,
44 pub media_type: String,
46 pub data: bytes::Bytes,
48}
49
50pub const MEDIA_TYPE_OCI_LAYER_GZIP: &str = "application/vnd.oci.image.layer.v1.tar+gzip";
52
53pub const MEDIA_TYPE_OCI_LAYER_TAR: &str = "application/vnd.oci.image.layer.v1.tar";
55
56pub const ARTIFACT_REF_KEY: &str = "__wfe_artifact";
58
59pub fn artifact_ref_value(digest: &str) -> serde_json::Value {
61 serde_json::json!({ ARTIFACT_REF_KEY: digest })
62}
63
64pub fn is_artifact_ref(value: &serde_json::Value) -> bool {
66 value
67 .as_object()
68 .map(|obj| obj.contains_key(ARTIFACT_REF_KEY))
69 .unwrap_or(false)
70}
71
72pub fn parse_artifact_ref(value: &serde_json::Value) -> Option<String> {
74 value
75 .as_object()
76 .and_then(|obj| obj.get(ARTIFACT_REF_KEY))
77 .and_then(|v| v.as_str())
78 .map(|s| s.to_string())
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn artifact_ref_roundtrip() {
87 let r = ArtifactRef::new("sha256:abc123");
88 assert_eq!(r.algorithm(), Some("sha256"));
89 assert_eq!(r.hash(), Some("abc123"));
90 }
91
92 #[test]
93 fn artifact_ref_value_is_artifact_ref() {
94 let v = artifact_ref_value("sha256:def456");
95 assert!(is_artifact_ref(&v));
96 assert_eq!(parse_artifact_ref(&v), Some("sha256:def456".to_string()));
97 }
98
99 #[test]
100 fn plain_string_is_not_artifact_ref() {
101 assert!(!is_artifact_ref(&serde_json::Value::String("hello".into())));
102 }
103}