Skip to main content

aliyun_oss/types/
storage.rs

1//! Storage class and server-side encryption types.
2
3use std::fmt;
4use std::str::FromStr;
5
6use crate::error::{ErrorContext, OssError, OssErrorKind};
7
8/// OSS storage class for object storage tiering.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
10pub enum StorageClass {
11    #[default]
12    Standard,
13    IA,
14    Archive,
15    ColdArchive,
16    DeepColdArchive,
17}
18
19impl StorageClass {
20    /// Returns the storage class string representation (e.g. "Standard").
21    pub fn as_str(self) -> &'static str {
22        match self {
23            Self::Standard => "Standard",
24            Self::IA => "IA",
25            Self::Archive => "Archive",
26            Self::ColdArchive => "ColdArchive",
27            Self::DeepColdArchive => "DeepColdArchive",
28        }
29    }
30}
31
32impl fmt::Display for StorageClass {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        f.write_str(self.as_str())
35    }
36}
37
38impl FromStr for StorageClass {
39    type Err = OssError;
40
41    fn from_str(s: &str) -> Result<Self, Self::Err> {
42        match s {
43            "Standard" => Ok(Self::Standard),
44            "IA" => Ok(Self::IA),
45            "Archive" => Ok(Self::Archive),
46            "ColdArchive" => Ok(Self::ColdArchive),
47            "DeepColdArchive" => Ok(Self::DeepColdArchive),
48            other => Err(OssError {
49                kind: OssErrorKind::ValidationError,
50                context: Box::new(ErrorContext {
51                    operation: Some(format!("parse StorageClass from '{}'", other)),
52                    ..Default::default()
53                }),
54                source: None,
55            }),
56        }
57    }
58}
59
60/// Data redundancy type: locally redundant (LRS) or zone-redundant (ZRS).
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
62pub enum DataRedundancyType {
63    #[default]
64    LRS,
65    ZRS,
66}
67
68impl DataRedundancyType {
69    /// Returns the redundancy type string (e.g. "LRS").
70    pub fn as_str(self) -> &'static str {
71        match self {
72            Self::LRS => "LRS",
73            Self::ZRS => "ZRS",
74        }
75    }
76}
77
78impl fmt::Display for DataRedundancyType {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        f.write_str(self.as_str())
81    }
82}
83
84/// Server-side encryption configuration for objects.
85#[derive(Debug, Clone, PartialEq, Eq)]
86pub enum ServerSideEncryption {
87    AES256,
88    KMS,
89    KMSWithKey(String),
90}
91
92impl ServerSideEncryption {
93    /// Returns the encryption algorithm identifier (e.g. "AES256").
94    pub fn as_str(&self) -> &str {
95        match self {
96            Self::AES256 => "AES256",
97            Self::KMS => "KMS",
98            Self::KMSWithKey(_) => "KMS",
99        }
100    }
101
102    /// Returns the KMS key ID, if configured.
103    pub fn key_id(&self) -> Option<&str> {
104        match self {
105            Self::KMSWithKey(key) => Some(key.as_str()),
106            _ => None,
107        }
108    }
109}
110
111impl fmt::Display for ServerSideEncryption {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        match self {
114            Self::KMSWithKey(key) => write!(f, "KMS:{}", key),
115            _ => f.write_str(self.as_str()),
116        }
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn storage_class_string_representation() {
126        assert_eq!(StorageClass::Standard.as_str(), "Standard");
127        assert_eq!(StorageClass::IA.as_str(), "IA");
128        assert_eq!(StorageClass::Archive.as_str(), "Archive");
129        assert_eq!(StorageClass::ColdArchive.as_str(), "ColdArchive");
130        assert_eq!(StorageClass::DeepColdArchive.as_str(), "DeepColdArchive");
131    }
132
133    #[test]
134    fn storage_class_default_is_standard() {
135        assert_eq!(StorageClass::default(), StorageClass::Standard);
136    }
137
138    #[test]
139    fn storage_class_from_str() {
140        assert_eq!(
141            "Standard".parse::<StorageClass>().unwrap(),
142            StorageClass::Standard
143        );
144        assert_eq!("IA".parse::<StorageClass>().unwrap(), StorageClass::IA);
145        assert!("Invalid".parse::<StorageClass>().is_err());
146    }
147
148    #[test]
149    fn storage_class_display() {
150        assert_eq!(StorageClass::Archive.to_string(), "Archive");
151    }
152
153    #[test]
154    fn data_redundancy_type_as_str() {
155        assert_eq!(DataRedundancyType::LRS.as_str(), "LRS");
156        assert_eq!(DataRedundancyType::ZRS.as_str(), "ZRS");
157    }
158
159    #[test]
160    fn server_side_encryption_string() {
161        assert_eq!(ServerSideEncryption::AES256.as_str(), "AES256");
162        assert_eq!(ServerSideEncryption::KMS.as_str(), "KMS");
163        assert_eq!(
164            ServerSideEncryption::KMSWithKey("cmk-id".into()).as_str(),
165            "KMS"
166        );
167    }
168
169    #[test]
170    fn server_side_encryption_key_id() {
171        assert!(ServerSideEncryption::AES256.key_id().is_none());
172        assert!(ServerSideEncryption::KMS.key_id().is_none());
173        assert_eq!(
174            ServerSideEncryption::KMSWithKey("my-key".into()).key_id(),
175            Some("my-key")
176        );
177    }
178
179    #[test]
180    fn server_side_encryption_display() {
181        assert_eq!(ServerSideEncryption::AES256.to_string(), "AES256");
182        assert_eq!(
183            ServerSideEncryption::KMSWithKey("my-key".into()).to_string(),
184            "KMS:my-key"
185        );
186    }
187
188    #[test]
189    fn storage_class_send_sync() {
190        fn assert_send_sync<T: Send + Sync>() {}
191        assert_send_sync::<StorageClass>();
192        assert_send_sync::<DataRedundancyType>();
193        assert_send_sync::<ServerSideEncryption>();
194    }
195}