1use std::collections::HashMap;
2use std::string::ToString;
3
4use heck::MixedCase;
5use serde::ser::Error;
6use serde::ser::SerializeMap;
7use serde::Serialize;
8use serde::Serializer;
9
10use crate::dsl::schema::object_types::bounds::ArrayItemObjectBounds;
11use crate::dsl::schema::object_types::bounds::ArrayObjectBounds;
12use crate::dsl::schema::object_types::bounds::ArrayUniqueItemBound;
13use crate::dsl::schema::object_types::bounds::DefaultValue;
14use crate::dsl::schema::object_types::bounds::EnumerationValue;
15use crate::dsl::schema::object_types::bounds::IntegerBound;
16use crate::dsl::schema::object_types::bounds::IntegerObjectBounds;
17use crate::dsl::schema::object_types::bounds::StringLength;
18use crate::dsl::schema::object_types::bounds::StringObjectBounds;
19use crate::dsl::schema::object_types::RawObjectType;
20use crate::dsl::schema::object_types::ObjectType;
21use crate::dsl::schema::object_types::bounds::BooleanObjectBounds;
22use crate::dsl::schema::KeysValues;
23
24impl Serialize for EnumerationValue {
25 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
26 where
27 S: Serializer,
28 {
29 let mut map = serializer.serialize_map(None)?;
30 if self.annotations.title.is_some() {
31 map.serialize_entry("title", &self.annotations.title)?;
32 map.serialize_entry("enum", &vec![&self.value])?;
33 }
34
35 map.end()
36 }
37}
38
39pub fn serialize_object_type<O, E, S>(object_type: &ObjectType, map: &mut S) -> Result<(), E>
40where
41 E: Error,
42 S: SerializeMap<Ok = O, Error = E>,
43{
44 let raw_type = object_type.inner_raw();
45 let default = object_type.data().default_value();
46
47 map.serialize_entry("type", object_type_name(raw_type))?;
48 serialize_default(default, map)?;
49
50 match raw_type {
51 RawObjectType::Object => {
52 map.serialize_entry(
53 "additionalProperties",
54 &object_type.data().allow_additional_properties(),
55 )?;
56 }
57 RawObjectType::Boolean(object_bounds) => serialize_boolean(object_bounds, map)?,
58 RawObjectType::String(object_bounds) => serialize_string(object_bounds, map)?,
59 RawObjectType::Text(object_bounds) => serialize_string(object_bounds, map)?,
60 RawObjectType::Password(object_bounds) => serialize_password(object_bounds, map)?,
61 RawObjectType::Integer(object_bounds) => serialize_integer(object_bounds, map)?,
62 RawObjectType::Number(object_bounds) => serialize_integer(object_bounds, map)?,
63 RawObjectType::Port(object_bounds) => serialize_integer(object_bounds, map)?,
64 RawObjectType::Array(object_bounds) => serialize_array(object_bounds, map)?,
65 RawObjectType::Stringlist(object_bounds) => serialize_array(object_bounds, map)?,
66
67 RawObjectType::Hostname(object_bounds) => serialize_string_with_format("hostname", object_bounds, map)?,
68 RawObjectType::Datetime(object_bounds) => serialize_string_with_format("date-time", object_bounds, map)?,
69 RawObjectType::Date(object_bounds) => serialize_string_with_format("date", object_bounds, map)?,
70 RawObjectType::Time(object_bounds) => serialize_string_with_format("time", object_bounds, map)?,
71 RawObjectType::Email(object_bounds) => serialize_string_with_format("email", object_bounds, map)?,
72 RawObjectType::IPV4(object_bounds) => serialize_string_with_format("ipv4", object_bounds, map)?,
73 RawObjectType::IPV6(object_bounds) => serialize_string_with_format("ipv6", object_bounds, map)?,
74 RawObjectType::URI(object_bounds) => serialize_string_with_format("uri", object_bounds, map)?,
75 RawObjectType::File(object_bounds) => serialize_string_with_format("data-url", object_bounds, map)?,
76
77 RawObjectType::DnsmasqAddress(object_bounds) => {
78 serialize_string_with_format("dnsmasq-address", object_bounds, map)?
79 }
80 RawObjectType::ChronyAddress(object_bounds) => {
81 serialize_string_with_format("chrony-address", object_bounds, map)?
82 }
83 RawObjectType::IpTablesAddress(object_bounds) => {
84 serialize_string_with_format("iptables-address", object_bounds, map)?
85 }
86 };
87 Ok(())
88}
89
90pub fn object_type_name(object_type: &RawObjectType) -> &str {
91 match object_type {
92 RawObjectType::Object => "object",
93 RawObjectType::Boolean(_) => "boolean",
94 RawObjectType::String(_) => "string",
95 RawObjectType::Text(_) => "string",
96 RawObjectType::Password(_) => "string",
97 RawObjectType::Integer(_) => "integer",
98 RawObjectType::Number(_) => "number",
99 RawObjectType::Port(_) => "integer",
100 RawObjectType::Array(_) => "array",
101 RawObjectType::Stringlist(_) => "array",
102
103 RawObjectType::Hostname(_) => "string",
104 RawObjectType::Datetime(_) => "string",
105 RawObjectType::Date(_) => "string",
106 RawObjectType::Time(_) => "string",
107 RawObjectType::Email(_) => "string",
108 RawObjectType::IPV4(_) => "string",
109 RawObjectType::IPV6(_) => "string",
110 RawObjectType::URI(_) => "string",
111
112 RawObjectType::File(_) => "string",
113
114 RawObjectType::DnsmasqAddress(_) => "string",
115 RawObjectType::ChronyAddress(_) => "string",
116 RawObjectType::IpTablesAddress(_) => "string",
117 }
118}
119
120pub fn serialize_keys_values<O, E, S>(keys_values: &KeysValues, map: &mut S) -> Result<(), E>
121where
122 E: Error,
123 S: SerializeMap<Ok = O, Error = E>,
124{
125 let mut pattern_properties = HashMap::new();
126 pattern_properties.insert(keys_values.keys.pattern.to_string(), &keys_values.values);
127 map.serialize_entry("patternProperties", &pattern_properties)?;
128 Ok(())
129}
130
131fn serialize_default<O, E, S>(default: &Option<DefaultValue>, map: &mut S) -> Result<(), E>
132where
133 E: Error,
134 S: SerializeMap<Ok = O, Error = E>,
135{
136 for value in default {
137 map.serialize_entry("default", value.value())?;
138 }
139 Ok(())
140}
141
142fn serialize_boolean<O, E, S>(bounds: &Option<BooleanObjectBounds>, map: &mut S) -> Result<(), E>
143where
144 E: Error,
145 S: SerializeMap<Ok = O, Error = E>,
146{
147 if let Some(bounds) = bounds {
148 serialize_enum_bounds(&bounds.0, map)?;
149 }
150 Ok(())
151}
152
153fn serialize_string<O, E, S>(bounds: &Option<StringObjectBounds>, map: &mut S) -> Result<(), E>
154where
155 E: Error,
156 S: SerializeMap<Ok = O, Error = E>,
157{
158 for enumeration_values in bounds {
159 serialize_string_bounds(&enumeration_values, map)?;
160 }
161 Ok(())
162}
163
164fn serialize_string_with_format<O, E, S>(
165 format: &str,
166 bounds: &Option<StringObjectBounds>,
167 map: &mut S,
168) -> Result<(), E>
169where
170 E: Error,
171 S: SerializeMap<Ok = O, Error = E>,
172{
173 map.serialize_entry("format", format)?;
174 serialize_string(bounds, map)
175}
176
177fn serialize_password<O, E, S>(bounds: &Option<StringObjectBounds>, map: &mut S) -> Result<(), E>
178where
179 E: Error,
180 S: SerializeMap<Ok = O, Error = E>,
181{
182 map.serialize_entry("writeOnly", &true)?;
183 serialize_string(bounds, map)?;
184 Ok(())
185}
186
187fn serialize_integer_bound<O, E, S>(name: &str, bound: &Option<IntegerBound>, map: &mut S) -> Result<(), E>
188where
189 E: Error,
190 S: SerializeMap<Ok = O, Error = E>,
191{
192 if let Some(value) = bound {
193 match value {
194 IntegerBound::Inclusive(value) => map.serialize_entry(name, &value)?,
195 IntegerBound::Exclusive(value) => {
196 map.serialize_entry(name, &value)?;
197 map.serialize_entry(&("exclusive ".to_string() + name).to_mixed_case(), &true)?;
198 }
199 }
200 }
201 Ok(())
202}
203
204fn serialize_array<O, E, S>(bounds: &Option<ArrayObjectBounds>, map: &mut S) -> Result<(), E>
205where
206 E: Error,
207 S: SerializeMap<Ok = O, Error = E>,
208{
209 if let Some(bounds) = bounds {
210 if let Some(max) = bounds.maximum_number_of_items {
211 map.serialize_entry("maxItems", &max)?;
212 }
213 if let Some(min) = bounds.minimum_number_of_items {
214 map.serialize_entry("minItems", &min)?;
215 }
216 if let Some(ref items) = bounds.items {
217 match items {
218 ArrayItemObjectBounds::AllItems(schema) => {
219 map.serialize_entry("items", &schema)?;
220 }
221 ArrayItemObjectBounds::AnyItems(schemas) => {
222 let mut wrapper = HashMap::new();
223 wrapper.insert("oneOf", schemas);
224 map.serialize_entry("items", &wrapper)?;
225 }
226 }
227 }
228 if let Some(ref unique_items) = bounds.unique_items {
229 match unique_items {
230 ArrayUniqueItemBound::All => {
231 map.serialize_entry("uniqueItems", &true)?;
232 }
233 ArrayUniqueItemBound::Specific(items) => {
234 map.serialize_entry("$$uniqueItemProperties", items)?;
235 }
236 }
237 }
238 }
239 Ok(())
240}
241
242fn serialize_integer<O, E, S>(bounds: &Option<IntegerObjectBounds>, map: &mut S) -> Result<(), E>
243where
244 E: Error,
245 S: SerializeMap<Ok = O, Error = E>,
246{
247 if let Some(bounds) = bounds {
248 match bounds {
249 IntegerObjectBounds::Conditions(conditions) => {
250 serialize_integer_bound("maximum", &conditions.maximum, map)?;
251 serialize_integer_bound("minimum", &conditions.minimum, map)?;
252 if let Some(multiple_of) = conditions.multiple_of {
253 map.serialize_entry("multipleOf", &multiple_of)?;
254 }
255 }
256 IntegerObjectBounds::Enumeration(list) => serialize_enum_bounds(list, map)?,
257 }
258 }
259 Ok(())
260}
261
262fn serialize_string_bounds<O, E, S>(string_bounds: &StringObjectBounds, map: &mut S) -> Result<(), E>
263where
264 E: Error,
265 S: SerializeMap<Ok = O, Error = E>,
266{
267 match string_bounds {
268 StringObjectBounds::Enumeration(values) => serialize_enum_bounds(values, map)?,
269 StringObjectBounds::Value(value_bounds) => {
270 if let Some(pattern) = &value_bounds.pattern {
271 map.serialize_entry("pattern", pattern.as_str())?
272 }
273 if let Some(length) = &value_bounds.length {
274 serialize_length_bounds(length, map)?
275 }
276 }
277 }
278 Ok(())
279}
280
281fn serialize_enum_bounds<O, E, S>(values: &[EnumerationValue], map: &mut S) -> Result<(), E>
282where
283 E: Error,
284 S: SerializeMap<Ok = O, Error = E>,
285{
286 if values.len() == 1 {
287 serialize_singular_constant_value(&values[0], map)?;
288 } else {
289 serialize_multiple_enum_values(&values, map)?;
290 }
291 Ok(())
292}
293
294fn serialize_length_bounds<O, E, S>(length_bounds: &StringLength, map: &mut S) -> Result<(), E>
295where
296 E: Error,
297 S: SerializeMap<Ok = O, Error = E>,
298{
299 if let Some(maximum) = length_bounds.maximum {
300 map.serialize_entry("maxLength", &maximum)?;
301 }
302 if let Some(minimum) = length_bounds.minimum {
303 map.serialize_entry("minLength", &minimum)?;
304 }
305 Ok(())
306}
307
308fn serialize_multiple_enum_values<O, E, S>(enumeration_values: &[EnumerationValue], map: &mut S) -> Result<(), E>
309where
310 E: Error,
311 S: SerializeMap<Ok = O, Error = E>,
312{
313 if !enumeration_values.is_empty() {
314 map.serialize_entry("oneOf", &enumeration_values)?;
315 }
316 Ok(())
317}
318
319fn serialize_singular_constant_value<O, E, S>(constant: &EnumerationValue, map: &mut S) -> Result<(), E>
320where
321 E: Error,
322 S: SerializeMap<Ok = O, Error = E>,
323{
324 Ok(map.serialize_entry("enum", &vec![constant.value.clone()]))?
325}