1use std::collections::BTreeMap;
12
13use qubit_common::{DataType, DataTypeOf};
14use qubit_value::{Value, ValueConstructor, ValueConverter};
15use serde::{Deserialize, Serialize};
16
17use crate::{MetadataError, MetadataResult, MetadataSchema};
18
19#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
29pub struct Metadata(BTreeMap<String, Value>);
30
31impl Metadata {
32 #[inline]
34 #[must_use]
35 pub fn new() -> Self {
36 Self(BTreeMap::new())
37 }
38
39 #[inline]
41 #[must_use]
42 pub fn is_empty(&self) -> bool {
43 self.0.is_empty()
44 }
45
46 #[inline]
48 #[must_use]
49 pub fn len(&self) -> usize {
50 self.0.len()
51 }
52
53 #[inline]
55 #[must_use]
56 pub fn contains_key(&self, key: &str) -> bool {
57 self.0.contains_key(key)
58 }
59
60 #[inline]
65 pub fn get<T>(&self, key: &str) -> Option<T>
66 where
67 T: DataTypeOf,
68 Value: ValueConverter<T>,
69 {
70 self.try_get(key).ok()
71 }
72
73 pub fn try_get<T>(&self, key: &str) -> MetadataResult<T>
81 where
82 T: DataTypeOf,
83 Value: ValueConverter<T>,
84 {
85 let value = self
86 .0
87 .get(key)
88 .ok_or_else(|| MetadataError::MissingKey(key.to_string()))?;
89 value
90 .to::<T>()
91 .map_err(|error| MetadataError::conversion_error(key, T::DATA_TYPE, value, error))
92 }
93
94 #[inline]
96 #[must_use]
97 pub fn get_raw(&self, key: &str) -> Option<&Value> {
98 self.0.get(key)
99 }
100
101 #[inline]
103 #[must_use]
104 pub fn data_type(&self, key: &str) -> Option<DataType> {
105 self.0.get(key).map(Value::data_type)
106 }
107
108 #[inline]
111 #[must_use]
112 pub fn get_or<T>(&self, key: &str, default: T) -> T
113 where
114 T: DataTypeOf,
115 Value: ValueConverter<T>,
116 {
117 self.try_get(key).unwrap_or(default)
118 }
119
120 #[inline]
122 pub fn set<T>(&mut self, key: &str, value: T) -> Option<Value>
123 where
124 Value: ValueConstructor<T>,
125 {
126 self.0.insert(key.to_string(), to_value(value))
127 }
128
129 #[inline]
137 pub fn set_checked<T>(
138 &mut self,
139 schema: &MetadataSchema,
140 key: &str,
141 value: T,
142 ) -> MetadataResult<Option<Value>>
143 where
144 Value: ValueConstructor<T>,
145 {
146 let value = to_value(value);
147 schema.validate_entry(key, &value)?;
148 Ok(self.set_raw(key, value))
149 }
150
151 #[inline]
159 pub fn with_checked<T>(
160 mut self,
161 schema: &MetadataSchema,
162 key: &str,
163 value: T,
164 ) -> MetadataResult<Self>
165 where
166 Value: ValueConstructor<T>,
167 {
168 self.set_checked(schema, key, value)?;
169 Ok(self)
170 }
171
172 #[inline]
174 #[must_use]
175 pub fn with<T>(mut self, key: &str, value: T) -> Self
176 where
177 Value: ValueConstructor<T>,
178 {
179 self.set(key, value);
180 self
181 }
182
183 #[inline]
185 pub fn set_raw(&mut self, key: &str, value: Value) -> Option<Value> {
186 self.0.insert(key.to_string(), value)
187 }
188
189 #[inline]
191 #[must_use]
192 pub fn with_raw(mut self, key: &str, value: Value) -> Self {
193 self.set_raw(key, value);
194 self
195 }
196
197 #[inline]
199 pub fn remove(&mut self, key: &str) -> Option<Value> {
200 self.0.remove(key)
201 }
202
203 #[inline]
205 pub fn clear(&mut self) {
206 self.0.clear();
207 }
208
209 #[inline]
211 pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
212 self.0.iter().map(|(key, value)| (key.as_str(), value))
213 }
214
215 #[inline]
217 pub fn keys(&self) -> impl Iterator<Item = &str> {
218 self.0.keys().map(String::as_str)
219 }
220
221 #[inline]
223 pub fn values(&self) -> impl Iterator<Item = &Value> {
224 self.0.values()
225 }
226
227 pub fn merge(&mut self, other: Metadata) {
229 for (key, value) in other.0 {
230 self.0.insert(key, value);
231 }
232 }
233
234 #[must_use]
238 pub fn merged(&self, other: &Metadata) -> Metadata {
239 let mut result = self.clone();
240 for (key, value) in &other.0 {
241 result.0.insert(key.clone(), value.clone());
242 }
243 result
244 }
245
246 #[inline]
248 pub fn retain<F>(&mut self, mut predicate: F)
249 where
250 F: FnMut(&str, &Value) -> bool,
251 {
252 self.0.retain(|key, value| predicate(key.as_str(), value));
253 }
254
255 #[inline]
257 #[must_use]
258 pub fn into_inner(self) -> BTreeMap<String, Value> {
259 self.0
260 }
261}
262
263#[inline]
264fn to_value<T>(value: T) -> Value
265where
266 Value: ValueConstructor<T>,
267{
268 <Value as ValueConstructor<T>>::from_type(value)
269}
270
271impl From<BTreeMap<String, Value>> for Metadata {
272 #[inline]
273 fn from(map: BTreeMap<String, Value>) -> Self {
274 Self(map)
275 }
276}
277
278impl From<Metadata> for BTreeMap<String, Value> {
279 #[inline]
280 fn from(meta: Metadata) -> Self {
281 meta.0
282 }
283}
284
285impl FromIterator<(String, Value)> for Metadata {
286 #[inline]
287 fn from_iter<I: IntoIterator<Item = (String, Value)>>(iter: I) -> Self {
288 Self(iter.into_iter().collect())
289 }
290}
291
292impl IntoIterator for Metadata {
293 type IntoIter = std::collections::btree_map::IntoIter<String, Value>;
294 type Item = (String, Value);
295
296 #[inline]
297 fn into_iter(self) -> Self::IntoIter {
298 self.0.into_iter()
299 }
300}
301
302impl<'a> IntoIterator for &'a Metadata {
303 type IntoIter = std::collections::btree_map::Iter<'a, String, Value>;
304 type Item = (&'a String, &'a Value);
305
306 #[inline]
307 fn into_iter(self) -> Self::IntoIter {
308 self.0.iter()
309 }
310}
311
312impl Extend<(String, Value)> for Metadata {
313 #[inline]
314 fn extend<I: IntoIterator<Item = (String, Value)>>(&mut self, iter: I) {
315 self.0.extend(iter);
316 }
317}