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