qubit_metadata/
metadata.rs1use std::collections::BTreeMap;
13
14use qubit_datatype::{
15 DataType,
16 DataTypeOf,
17};
18use qubit_value::Value;
19use serde::{
20 Deserialize,
21 Serialize,
22};
23
24use crate::{
25 FromMetadataValue,
26 IntoMetadataValue,
27 MetadataError,
28 MetadataResult,
29 MetadataSchema,
30};
31
32#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
42pub struct Metadata(BTreeMap<String, Value>);
43
44impl Metadata {
45 #[inline]
47 #[must_use]
48 pub fn new() -> Self {
49 Self(BTreeMap::new())
50 }
51
52 #[inline]
54 #[must_use]
55 pub fn is_empty(&self) -> bool {
56 self.0.is_empty()
57 }
58
59 #[inline]
61 #[must_use]
62 pub fn len(&self) -> usize {
63 self.0.len()
64 }
65
66 #[inline]
68 #[must_use]
69 pub fn contains_key(&self, key: &str) -> bool {
70 self.0.contains_key(key)
71 }
72
73 #[inline]
78 pub fn get<T>(&self, key: &str) -> Option<T>
79 where
80 T: DataTypeOf + FromMetadataValue,
81 {
82 self.try_get(key).ok()
83 }
84
85 pub fn try_get<T>(&self, key: &str) -> MetadataResult<T>
93 where
94 T: DataTypeOf + FromMetadataValue,
95 {
96 let value = self
97 .0
98 .get(key)
99 .ok_or_else(|| MetadataError::MissingKey(key.to_string()))?;
100 T::from_metadata_value(value)
101 .map_err(|error| MetadataError::conversion_error(key, T::DATA_TYPE, value, error))
102 }
103
104 #[inline]
106 #[must_use]
107 pub fn get_raw(&self, key: &str) -> Option<&Value> {
108 self.0.get(key)
109 }
110
111 #[inline]
113 #[must_use]
114 pub fn data_type(&self, key: &str) -> Option<DataType> {
115 self.0.get(key).map(Value::data_type)
116 }
117
118 #[inline]
121 #[must_use]
122 pub fn get_or<T>(&self, key: &str, default: T) -> T
123 where
124 T: DataTypeOf + FromMetadataValue,
125 {
126 self.try_get(key).unwrap_or(default)
127 }
128
129 #[inline]
131 pub fn set<T>(&mut self, key: &str, value: T) -> Option<Value>
132 where
133 T: IntoMetadataValue,
134 {
135 self.0.insert(key.to_string(), value.into_metadata_value())
136 }
137
138 #[inline]
146 pub fn set_checked<T>(
147 &mut self,
148 schema: &MetadataSchema,
149 key: &str,
150 value: T,
151 ) -> MetadataResult<Option<Value>>
152 where
153 T: IntoMetadataValue,
154 {
155 let value = value.into_metadata_value();
156 schema.validate_entry(key, &value)?;
157 Ok(self.set_raw(key, value))
158 }
159
160 #[inline]
168 pub fn with_checked<T>(
169 mut self,
170 schema: &MetadataSchema,
171 key: &str,
172 value: T,
173 ) -> MetadataResult<Self>
174 where
175 T: IntoMetadataValue,
176 {
177 self.set_checked(schema, key, value)?;
178 Ok(self)
179 }
180
181 #[inline]
183 #[must_use]
184 pub fn with<T>(mut self, key: &str, value: T) -> Self
185 where
186 T: IntoMetadataValue,
187 {
188 self.set(key, value);
189 self
190 }
191
192 #[inline]
194 pub fn set_raw(&mut self, key: &str, value: Value) -> Option<Value> {
195 self.0.insert(key.to_string(), value)
196 }
197
198 #[inline]
200 #[must_use]
201 pub fn with_raw(mut self, key: &str, value: Value) -> Self {
202 self.set_raw(key, value);
203 self
204 }
205
206 #[inline]
208 pub fn remove(&mut self, key: &str) -> Option<Value> {
209 self.0.remove(key)
210 }
211
212 #[inline]
214 pub fn clear(&mut self) {
215 self.0.clear();
216 }
217
218 #[inline]
220 pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
221 self.0.iter().map(|(key, value)| (key.as_str(), value))
222 }
223
224 #[inline]
226 pub fn keys(&self) -> impl Iterator<Item = &str> {
227 self.0.keys().map(String::as_str)
228 }
229
230 #[inline]
232 pub fn values(&self) -> impl Iterator<Item = &Value> {
233 self.0.values()
234 }
235
236 pub fn merge(&mut self, other: Metadata) {
238 for (key, value) in other.0 {
239 self.0.insert(key, value);
240 }
241 }
242
243 #[must_use]
247 pub fn merged(&self, other: &Metadata) -> Metadata {
248 let mut result = self.clone();
249 for (key, value) in &other.0 {
250 result.0.insert(key.clone(), value.clone());
251 }
252 result
253 }
254
255 #[inline]
257 pub fn retain<F>(&mut self, mut predicate: F)
258 where
259 F: FnMut(&str, &Value) -> bool,
260 {
261 self.0.retain(|key, value| predicate(key.as_str(), value));
262 }
263
264 #[inline]
266 #[must_use]
267 pub fn into_inner(self) -> BTreeMap<String, Value> {
268 self.0
269 }
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}