qubit_metadata/schema/
metadata_schema.rs1use std::collections::BTreeMap;
13
14use qubit_datatype::DataType;
15use qubit_value::Value;
16use serde::{Deserialize, Serialize};
17
18use crate::schema::{MetadataField, MetadataSchemaBuilder, UnknownFieldPolicy};
19use crate::{Metadata, MetadataError, MetadataResult};
20
21#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
27pub struct MetadataSchema {
28 fields: BTreeMap<String, MetadataField>,
30 unknown_field_policy: UnknownFieldPolicy,
32}
33
34impl MetadataSchema {
35 #[inline]
37 #[must_use]
38 pub fn builder() -> MetadataSchemaBuilder {
39 MetadataSchemaBuilder::default()
40 }
41
42 #[inline]
44 pub(crate) fn new(
45 fields: BTreeMap<String, MetadataField>,
46 unknown_field_policy: UnknownFieldPolicy,
47 ) -> Self {
48 Self {
49 fields,
50 unknown_field_policy,
51 }
52 }
53
54 #[inline]
56 #[must_use]
57 pub fn field(&self, key: &str) -> Option<&MetadataField> {
58 self.fields.get(key)
59 }
60
61 #[inline]
63 #[must_use]
64 pub fn field_type(&self, key: &str) -> Option<DataType> {
65 self.field(key).map(MetadataField::data_type)
66 }
67
68 #[inline]
70 #[must_use]
71 pub fn unknown_field_policy(&self) -> UnknownFieldPolicy {
72 self.unknown_field_policy
73 }
74
75 #[inline]
77 pub fn fields(&self) -> impl Iterator<Item = (&str, &MetadataField)> {
78 self.fields.iter().map(|(key, field)| (key.as_str(), field))
79 }
80
81 pub fn validate(&self, meta: &Metadata) -> MetadataResult<()> {
89 for (key, field) in &self.fields {
90 if field.is_required() && !meta.contains_key(key) {
91 return Err(MetadataError::MissingRequiredField {
92 key: key.clone(),
93 expected: field.data_type(),
94 });
95 }
96 }
97
98 for (key, value) in meta.iter() {
99 self.validate_entry(key, value)?;
100 }
101 Ok(())
102 }
103
104 pub(crate) fn validate_entry(&self, key: &str, value: &Value) -> MetadataResult<()> {
106 match self.field(key) {
107 Some(field) if field.data_type() != value.data_type() => Err(
108 MetadataError::type_mismatch(key, field.data_type(), value.data_type()),
109 ),
110 Some(_) => Ok(()),
111 None if matches!(self.unknown_field_policy, UnknownFieldPolicy::Reject) => {
112 Err(MetadataError::UnknownField {
113 key: key.to_string(),
114 })
115 }
116 None => Ok(()),
117 }
118 }
119}
120
121impl Default for MetadataSchema {
122 #[inline]
123 fn default() -> Self {
124 Self {
125 fields: BTreeMap::new(),
126 unknown_field_policy: UnknownFieldPolicy::Reject,
127 }
128 }
129}