object_store/
attributes.rs1use std::borrow::Cow;
19use std::collections::HashMap;
20use std::ops::Deref;
21
22#[non_exhaustive]
24#[derive(Debug, Hash, Eq, PartialEq, Clone)]
25pub enum Attribute {
26 ContentDisposition,
30 ContentEncoding,
34 ContentLanguage,
38 ContentType,
44 CacheControl,
48 Metadata(Cow<'static, str>),
52}
53
54#[derive(Debug, Hash, Eq, PartialEq, Clone)]
66pub struct AttributeValue(Cow<'static, str>);
67
68impl AsRef<str> for AttributeValue {
69 fn as_ref(&self) -> &str {
70 &self.0
71 }
72}
73
74impl From<&'static str> for AttributeValue {
75 fn from(value: &'static str) -> Self {
76 Self(Cow::Borrowed(value))
77 }
78}
79
80impl From<String> for AttributeValue {
81 fn from(value: String) -> Self {
82 Self(Cow::Owned(value))
83 }
84}
85
86impl Deref for AttributeValue {
87 type Target = str;
88
89 fn deref(&self) -> &Self::Target {
90 self.0.as_ref()
91 }
92}
93
94#[derive(Debug, Default, Eq, PartialEq, Clone)]
102pub struct Attributes(HashMap<Attribute, AttributeValue>);
103
104impl Attributes {
105 pub fn new() -> Self {
107 Self::default()
108 }
109
110 pub fn with_capacity(capacity: usize) -> Self {
112 Self(HashMap::with_capacity(capacity))
113 }
114
115 pub fn insert(&mut self, key: Attribute, value: AttributeValue) -> Option<AttributeValue> {
119 self.0.insert(key, value)
120 }
121
122 pub fn get(&self, key: &Attribute) -> Option<&AttributeValue> {
124 self.0.get(key)
125 }
126
127 pub fn remove(&mut self, key: &Attribute) -> Option<AttributeValue> {
129 self.0.remove(key)
130 }
131
132 pub fn iter(&self) -> AttributesIter<'_> {
134 self.into_iter()
135 }
136
137 #[inline]
139 pub fn len(&self) -> usize {
140 self.0.len()
141 }
142
143 #[inline]
145 pub fn is_empty(&self) -> bool {
146 self.0.is_empty()
147 }
148}
149
150impl<K, V> FromIterator<(K, V)> for Attributes
151where
152 K: Into<Attribute>,
153 V: Into<AttributeValue>,
154{
155 fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
156 Self(
157 iter.into_iter()
158 .map(|(k, v)| (k.into(), v.into()))
159 .collect(),
160 )
161 }
162}
163
164impl<'a> IntoIterator for &'a Attributes {
165 type Item = (&'a Attribute, &'a AttributeValue);
166 type IntoIter = AttributesIter<'a>;
167
168 fn into_iter(self) -> Self::IntoIter {
169 AttributesIter(self.0.iter())
170 }
171}
172
173#[derive(Debug)]
175pub struct AttributesIter<'a>(std::collections::hash_map::Iter<'a, Attribute, AttributeValue>);
176
177impl<'a> Iterator for AttributesIter<'a> {
178 type Item = (&'a Attribute, &'a AttributeValue);
179
180 fn next(&mut self) -> Option<Self::Item> {
181 self.0.next()
182 }
183
184 fn size_hint(&self) -> (usize, Option<usize>) {
185 self.0.size_hint()
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn test_attributes_basic() {
195 let mut attributes = Attributes::from_iter([
196 (Attribute::ContentDisposition, "inline"),
197 (Attribute::ContentEncoding, "gzip"),
198 (Attribute::ContentLanguage, "en-US"),
199 (Attribute::ContentType, "test"),
200 (Attribute::CacheControl, "control"),
201 (Attribute::Metadata("key1".into()), "value1"),
202 ]);
203
204 assert!(!attributes.is_empty());
205 assert_eq!(attributes.len(), 6);
206
207 assert_eq!(
208 attributes.get(&Attribute::ContentType),
209 Some(&"test".into())
210 );
211
212 let metav = "control".into();
213 assert_eq!(attributes.get(&Attribute::CacheControl), Some(&metav));
214 assert_eq!(
215 attributes.insert(Attribute::CacheControl, "v1".into()),
216 Some(metav)
217 );
218 assert_eq!(attributes.len(), 6);
219
220 assert_eq!(
221 attributes.remove(&Attribute::CacheControl).unwrap(),
222 "v1".into()
223 );
224 assert_eq!(attributes.len(), 5);
225
226 let metav: AttributeValue = "v2".into();
227 attributes.insert(Attribute::CacheControl, metav.clone());
228 assert_eq!(attributes.get(&Attribute::CacheControl), Some(&metav));
229 assert_eq!(attributes.len(), 6);
230
231 assert_eq!(
232 attributes.get(&Attribute::ContentDisposition),
233 Some(&"inline".into())
234 );
235 assert_eq!(
236 attributes.get(&Attribute::ContentEncoding),
237 Some(&"gzip".into())
238 );
239 assert_eq!(
240 attributes.get(&Attribute::ContentLanguage),
241 Some(&"en-US".into())
242 );
243 assert_eq!(
244 attributes.get(&Attribute::Metadata("key1".into())),
245 Some(&"value1".into())
246 );
247 }
248}