Skip to main content

entrenar/storage/cloud/
metadata.rs

1//! Artifact metadata types
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6/// Artifact metadata
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct ArtifactMetadata {
9    /// Original filename
10    pub name: String,
11    /// Content-addressable hash (SHA-256)
12    pub hash: String,
13    /// Size in bytes
14    pub size: u64,
15    /// Content type (MIME)
16    pub content_type: Option<String>,
17    /// Creation timestamp (Unix seconds)
18    pub created_at: u64,
19    /// Custom metadata
20    pub metadata: HashMap<String, String>,
21}
22
23impl ArtifactMetadata {
24    /// Create new artifact metadata
25    pub fn new(name: &str, hash: &str, size: u64) -> Self {
26        Self {
27            name: name.to_string(),
28            hash: hash.to_string(),
29            size,
30            content_type: None,
31            created_at: std::time::SystemTime::now()
32                .duration_since(std::time::UNIX_EPOCH)
33                .map(|d| d.as_secs())
34                .unwrap_or(0),
35            metadata: HashMap::new(),
36        }
37    }
38
39    /// Set content type
40    pub fn with_content_type(mut self, content_type: &str) -> Self {
41        self.content_type = Some(content_type.to_string());
42        self
43    }
44
45    /// Add custom metadata
46    pub fn with_metadata(mut self, key: &str, value: &str) -> Self {
47        self.metadata.insert(key.to_string(), value.to_string());
48        self
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn test_artifact_metadata_new() {
58        let meta = ArtifactMetadata::new("test.bin", "abc123", 1024);
59        assert_eq!(meta.name, "test.bin");
60        assert_eq!(meta.hash, "abc123");
61        assert_eq!(meta.size, 1024);
62    }
63
64    #[test]
65    fn test_artifact_metadata_with_content_type() {
66        let meta = ArtifactMetadata::new("model.safetensors", "abc", 100)
67            .with_content_type("application/octet-stream");
68        assert_eq!(meta.content_type, Some("application/octet-stream".to_string()));
69    }
70
71    #[test]
72    fn test_artifact_metadata_with_metadata() {
73        let meta = ArtifactMetadata::new("model.bin", "abc123", 1024)
74            .with_metadata("model_type", "bert")
75            .with_metadata("version", "1.0");
76        assert_eq!(meta.metadata.get("model_type"), Some(&"bert".to_string()));
77        assert_eq!(meta.metadata.get("version"), Some(&"1.0".to_string()));
78    }
79
80    #[test]
81    fn test_artifact_metadata_serde() {
82        let meta = ArtifactMetadata::new("test.bin", "abc123", 1024)
83            .with_content_type("application/octet-stream")
84            .with_metadata("key", "value");
85
86        let json = serde_json::to_string(&meta).expect("JSON serialization should succeed");
87        let parsed: ArtifactMetadata =
88            serde_json::from_str(&json).expect("JSON deserialization should succeed");
89
90        assert_eq!(meta.name, parsed.name);
91        assert_eq!(meta.hash, parsed.hash);
92        assert_eq!(meta.size, parsed.size);
93        assert_eq!(meta.content_type, parsed.content_type);
94    }
95
96    #[test]
97    fn test_artifact_metadata_created_at_is_set() {
98        let meta = ArtifactMetadata::new("test.bin", "hash", 100);
99        assert!(meta.created_at > 0);
100    }
101}