yaml_schema/schemas/
base.rs1use std::collections::HashMap;
2
3use saphyr::AnnotatedMapping;
4use saphyr::MarkedYaml;
5use saphyr::Scalar;
6use saphyr::YamlData;
7
8use crate::ConstValue;
9use crate::schemas::SchemaMetadata;
10use crate::schemas::r#enum::load_enum_values;
11use crate::utils::format_marker;
12
13#[derive(Debug, Default, PartialEq)]
15pub struct BaseSchema {
16 pub r#enum: Option<Vec<ConstValue>>,
17 pub r#const: Option<ConstValue>,
18 pub description: Option<String>,
19}
20
21impl BaseSchema {
22 pub fn as_hash_map(&self) -> HashMap<String, String> {
23 let mut h = HashMap::new();
24 if let Some(r#enum) = &self.r#enum {
25 h.insert(
26 "enum".to_string(),
27 r#enum
28 .iter()
29 .map(|v| v.to_string())
30 .collect::<Vec<String>>()
31 .join(", "),
32 );
33 }
34 if let Some(r#const) = &self.r#const {
35 h.insert("const".to_string(), r#const.to_string());
36 }
37 h
38 }
39
40 pub fn handle_key_value(
41 &mut self,
42 key: &str,
43 value: &MarkedYaml,
44 ) -> crate::Result<Option<&Self>> {
45 match key {
46 "enum" => {
47 if let YamlData::Sequence(values) = &value.data {
48 self.r#enum = Some(load_enum_values(values)?);
49 Ok(Some(self))
50 } else {
51 Err(expected_scalar!(
52 "{} Expected an array for enum:, but got: {:#?}",
53 format_marker(&value.span.start),
54 value
55 ))
56 }
57 }
58 "const" => {
59 if let YamlData::Value(scalar) = &value.data {
60 let const_value: ConstValue = scalar.try_into()?;
61 self.r#const = Some(const_value);
62 Ok(Some(self))
63 } else {
64 Err(expected_scalar!(
65 "{} Expecting scalar value for const, got {:?}",
66 format_marker(&value.span.start),
67 value
68 ))
69 }
70 }
71 "description" => {
72 if let YamlData::Value(Scalar::String(value)) = &value.data {
73 self.description = Some(value.to_string());
74 Ok(Some(self))
75 } else {
76 Err(expected_scalar!(
77 "{} Expected a string value for description, got {:?}",
78 format_marker(&value.span.start),
79 value
80 ))
81 }
82 }
83 _ => Ok(None),
84 }
85 }
86}
87
88impl SchemaMetadata for BaseSchema {
89 fn get_accepted_keys() -> &'static [&'static str] {
90 &["type", "enum", "const", "description"]
91 }
92}
93
94impl TryFrom<&MarkedYaml<'_>> for BaseSchema {
95 type Error = crate::Error;
96
97 fn try_from(value: &MarkedYaml) -> Result<Self, Self::Error> {
98 if let YamlData::Mapping(mapping) = &value.data {
99 Ok(BaseSchema::try_from(mapping)?)
100 } else {
101 Err(expected_mapping!(value))
102 }
103 }
104}
105
106impl TryFrom<&AnnotatedMapping<'_, MarkedYaml<'_>>> for BaseSchema {
107 type Error = crate::Error;
108
109 fn try_from(mapping: &AnnotatedMapping<'_, MarkedYaml<'_>>) -> crate::Result<Self> {
110 let mut base_schema = BaseSchema::default();
111 for (key, value) in mapping.iter() {
112 if let YamlData::Value(Scalar::String(key)) = &key.data {
113 base_schema.handle_key_value(key, value)?;
114 } else {
115 return Err(generic_error!(
116 "{} Expected string key, got {:?}",
117 format_marker(&key.span.start),
118 key
119 ));
120 }
121 }
122 Ok(base_schema)
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use saphyr::LoadableYamlNode as _;
129
130 use super::*;
131
132 #[test]
133 fn test_base_schema_with_enum() {
134 let yaml = r#"
135 type: string
136 enum:
137 - "foo"
138 - "bar"
139 "#;
140 let doc = MarkedYaml::load_from_str(yaml).unwrap();
141 let marked_yaml = doc.first().unwrap();
142 let base_schema = BaseSchema::try_from(marked_yaml).unwrap();
143 assert_eq!(
144 base_schema.r#enum,
145 Some(vec![
146 ConstValue::String("foo".to_string()),
147 ConstValue::String("bar".to_string())
148 ])
149 );
150 }
151}