Skip to main content

systemprompt_traits/
storage.rs

1//! File storage trait and identifier types.
2//!
3//! Defines the [`FileStorage`] abstraction implemented by every storage
4//! backend (local disk, object stores, cloud blob services), along with the
5//! [`StoredFileId`] / [`StoredFileMetadata`] value types returned across the
6//! storage boundary. Errors are reported as [`FileStorageError`] so that
7//! callers can match on cause rather than parsing strings.
8
9use async_trait::async_trait;
10use std::path::Path;
11
12pub type FileStorageResult<T> = Result<T, FileStorageError>;
13
14#[derive(Debug, thiserror::Error)]
15#[non_exhaustive]
16pub enum FileStorageError {
17    #[error("file not found: {0}")]
18    NotFound(String),
19
20    #[error("validation failed: {0}")]
21    Validation(String),
22
23    #[error("io error: {0}")]
24    Io(#[from] std::io::Error),
25
26    #[error("serialization error: {0}")]
27    Serialization(#[from] serde_json::Error),
28
29    #[error("storage backend error: {0}")]
30    Backend(String),
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash)]
34pub struct StoredFileId(pub String);
35
36impl StoredFileId {
37    #[must_use]
38    pub fn new(id: impl Into<String>) -> Self {
39        Self(id.into())
40    }
41
42    #[must_use]
43    pub fn as_str(&self) -> &str {
44        &self.0
45    }
46}
47
48impl From<String> for StoredFileId {
49    fn from(s: String) -> Self {
50        Self(s)
51    }
52}
53
54impl From<&str> for StoredFileId {
55    fn from(s: &str) -> Self {
56        Self(s.to_string())
57    }
58}
59
60impl std::fmt::Display for StoredFileId {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        write!(f, "{}", self.0)
63    }
64}
65
66#[derive(Debug, Clone)]
67pub struct StoredFileMetadata {
68    pub id: StoredFileId,
69    pub path: String,
70    pub mime_type: String,
71    pub size_bytes: Option<i64>,
72    pub created_at: chrono::DateTime<chrono::Utc>,
73    pub updated_at: chrono::DateTime<chrono::Utc>,
74}
75
76#[async_trait]
77pub trait FileStorage: Send + Sync {
78    async fn store(&self, path: &Path, content: &[u8]) -> FileStorageResult<StoredFileId>;
79
80    async fn retrieve(&self, id: &StoredFileId) -> FileStorageResult<Vec<u8>>;
81
82    async fn delete(&self, id: &StoredFileId) -> FileStorageResult<()>;
83
84    async fn metadata(&self, id: &StoredFileId) -> FileStorageResult<StoredFileMetadata>;
85
86    async fn exists(&self, id: &StoredFileId) -> FileStorageResult<bool>;
87
88    fn public_url(&self, _id: &StoredFileId) -> Option<String> {
89        None
90    }
91}