1use serde::{Deserialize, Serialize};
2use std::{
3 collections::{HashMap, HashSet},
4 fmt,
5};
6
7#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
9#[serde(default)]
10pub struct DataModel {
11 pub data_types: Vec<DataType>,
13 pub headers: HashMap<String, String>,
15 pub footers: HashMap<String, String>,
17 pub namespace: Vec<String>,
19 pub macros: HashMap<String, SerializationModel>,
21}
22
23impl DataModel {
24 pub fn export_yaml(&self) -> Result<String, serde_yaml::Error> {
26 return serde_yaml::to_string(self);
27 }
28
29 pub fn export_json(&self) -> Result<String, serde_json::Error> {
31 return serde_json::to_string(self);
32 }
33
34 pub fn import_yaml(mode: &str) -> Result<DataModel, serde_yaml::Error> {
36 return serde_yaml::from_value(sanitize_yaml(serde_yaml::from_str(mode)?));
37 }
38
39 pub fn import_json(mode: &str) -> Result<DataModel, serde_json::Error> {
41 return serde_json::from_value(sanitize_json(serde_json::from_str(mode)?));
42 }
43}
44
45fn sanitize_yaml(value: serde_yaml::Value) -> serde_yaml::Value {
46 match value {
47 serde_yaml::Value::Bool(value) => {
48 if value {
49 serde_yaml::Value::String("true".to_string())
50 } else {
51 serde_yaml::Value::String("false".to_string())
52 }
53 }
54 serde_yaml::Value::Mapping(value) => serde_yaml::Value::Mapping(
55 value
56 .into_iter()
57 .map(|(k, v)| (k, sanitize_yaml(v)))
58 .collect(),
59 ),
60 serde_yaml::Value::Number(value) => serde_yaml::Value::String(value.to_string()),
61 serde_yaml::Value::Sequence(value) => {
62 serde_yaml::Value::Sequence(value.into_iter().map(sanitize_yaml).collect())
63 }
64 serde_yaml::Value::Tagged(value) => {
65 serde_yaml::Value::Tagged(Box::new(serde_yaml::value::TaggedValue {
66 tag: value.tag,
67 value: sanitize_yaml(value.value),
68 }))
69 }
70 _ => value,
71 }
72}
73
74fn sanitize_json(value: serde_json::Value) -> serde_json::Value {
75 match value {
76 serde_json::Value::Bool(value) => {
77 if value {
78 serde_json::Value::String("true".to_string())
79 } else {
80 serde_json::Value::String("false".to_string())
81 }
82 }
83 serde_json::Value::Object(value) => serde_json::Value::Object(
84 value
85 .into_iter()
86 .map(|(k, v)| (k, sanitize_json(v)))
87 .collect(),
88 ),
89 serde_json::Value::Number(value) => serde_json::Value::String(value.to_string()),
90 serde_json::Value::Array(value) => {
91 serde_json::Value::Array(value.into_iter().map(sanitize_json).collect())
92 }
93 _ => value,
94 }
95}
96
97#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
99pub struct DataType {
100 pub name: String,
102 pub description: Option<String>,
104 pub data: DataTypeData,
106}
107
108#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
110pub enum DataTypeData {
111 Struct(Struct),
113 Array(Array),
115 Variant(Variant),
117 Enum(Enum),
119 ConstrainedType(ConstrainedType),
121}
122
123#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
128pub struct Struct {
129 pub fields: Vec<StructField>,
131 pub inherit: Option<String>,
134}
135
136#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
138pub struct StructField {
139 pub name: String,
141 pub description: Option<String>,
143 pub data_type: String,
145 pub default: DefaultType,
147}
148
149#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
151pub struct Array {
152 pub data_type: String,
154}
155
156#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
159pub struct Variant {
160 pub data_types: Vec<String>,
162}
163
164#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
166pub struct Enum {
167 pub types: Vec<EnumType>,
169}
170
171#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
173pub struct EnumType {
174 pub name: String,
176 pub description: Option<String>,
178 pub data_type: Option<String>,
180}
181
182#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
184pub struct ConstrainedType {
185 pub data_type: String,
187 pub constraints: Vec<Constraint>,
190}
191
192#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
194pub enum Constraint {
195 Arithmetic(String),
197 Function(String),
200}
201
202#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
204pub enum DefaultType {
205 Required,
207 Optional,
210 Default(SerializationModel),
213}
214
215#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
217#[serde(untagged)]
218pub enum SerializationModel {
219 Map(HashMap<String, SerializationModel>),
221 Array(Vec<SerializationModel>),
223 Value(String),
225}
226
227pub(crate) fn expand_macros<'a>(
237 value: &SerializationModel,
238 macros: &'a HashMap<String, SerializationModel>,
239 used_macros: &mut HashSet<&'a str>,
240) -> Result<SerializationModel, Error> {
241 return match value {
242 SerializationModel::Map(value) => value
243 .iter()
244 .map(|(k, v)| match expand_macros(v, macros, used_macros) {
245 Ok(value) => Ok((k.clone(), value)),
246 Err(error) => Err(error.add_field(k)),
247 })
248 .collect::<Result<HashMap<_, _>, _>>()
249 .map(SerializationModel::Map),
250 SerializationModel::Array(value) => value
251 .iter()
252 .enumerate()
253 .map(|(i, v)| match expand_macros(v, macros, used_macros) {
254 Ok(value) => Ok(value),
255 Err(error) => Err(error.add_element(i)),
256 })
257 .collect::<Result<Vec<_>, _>>()
258 .map(SerializationModel::Array),
259 SerializationModel::Value(value) => {
260 if value.starts_with('$')
262 && value.ends_with('$')
263 && value.len() > 2
264 && value.chars().filter(|c| *c == '$').count() == 2
265 {
266 let macro_name = &value[1..value.len() - 1];
267
268 if used_macros.contains(macro_name) {
270 return Err(Error {
271 location: "".to_string(),
272 error: ErrorCore::RecursiveMacro(macro_name.to_string()),
273 });
274 }
275
276 return if let Some((macro_key, macro_value)) = macros.get_key_value(macro_name) {
278 used_macros.insert(macro_key.as_str());
279 let expanded_macro = expand_macros(macro_value, macros, used_macros);
280 used_macros.remove(macro_key.as_str());
281 match expanded_macro {
282 Ok(value) => Ok(value),
283 Err(error) => Err(error.add_macro(macro_name)),
284 }
285 } else {
286 Err(Error {
287 location: "".to_string(),
288 error: ErrorCore::MissingMacro(macro_name.to_string()),
289 })
290 };
291 }
292
293 let mut expanded_string = String::new();
295 let mut current_index = 0;
296 while current_index < value.len() {
297 if let Some(start_index) = value[current_index..].find('$') {
299 let start_index = start_index + current_index + 1;
300 expanded_string.push_str(&value[current_index..start_index - 1]);
301
302 if start_index < value.len() && &value[start_index..start_index + 1] == "$" {
304 expanded_string.push('$');
305 current_index = start_index + 1;
306 continue;
307 }
308
309 if let Some(end_index) = value[start_index..].find('$') {
311 let end_index = end_index + start_index;
312 let macro_name = &value[start_index..end_index];
313
314 if used_macros.contains(macro_name) {
316 return Err(Error {
317 location: "".to_string(),
318 error: ErrorCore::RecursiveMacro(macro_name.to_string()),
319 });
320 }
321
322 if let Some((macro_key, macro_value)) = macros.get_key_value(macro_name) {
323 used_macros.insert(macro_key.as_str());
325 let expanded_macro = expand_macros(macro_value, macros, used_macros);
326 used_macros.remove(macro_key.as_str());
327 match expanded_macro {
328 Ok(ok_value) => match ok_value {
329 SerializationModel::Value(value) => {
330 expanded_string.push_str(&value);
331 }
332 _ => {
333 return Err(Error {
334 location: "".to_string(),
335 error: ErrorCore::PartialMacro(
336 macro_name.to_string(),
337 value.clone(),
338 ),
339 });
340 }
341 },
342 Err(error) => {
343 return Err(error.add_macro(macro_name));
344 }
345 }
346 } else {
347 return Err(Error {
348 location: "".to_string(),
349 error: ErrorCore::MissingMacro(macro_name.to_string()),
350 });
351 }
352
353 current_index = end_index + 1;
354 } else {
355 return Err(Error {
356 location: "".to_string(),
357 error: ErrorCore::IncompleteMacro(value.clone()),
358 });
359 }
360 } else {
361 expanded_string.push_str(&value[current_index..]);
362 break;
363 }
364 }
365
366 Ok(SerializationModel::Value(expanded_string))
367 }
368 };
369}
370
371#[derive(Debug, Clone)]
374pub struct Error {
375 pub location: String,
377 pub error: ErrorCore,
379}
380
381impl Error {
382 fn add_field(self, base: &str) -> Error {
388 let location = format!(".{}{}", base, self.location);
389
390 return Error {
391 location,
392 error: self.error,
393 };
394 }
395
396 fn add_element(self, index: usize) -> Error {
402 let location = format!("[{}]{}", index, self.location);
403
404 return Error {
405 location,
406 error: self.error,
407 };
408 }
409
410 fn add_macro(self, index: &str) -> Error {
416 let location = format!("[{}]{}", index, self.location);
417
418 return Error {
419 location,
420 error: self.error,
421 };
422 }
423}
424
425impl fmt::Display for Error {
426 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
427 return write!(f, "{}: {}", self.location, self.error);
428 }
429}
430
431#[derive(thiserror::Error, Debug, Clone)]
433pub enum ErrorCore {
434 #[error("The macro \"{}\" is used recursively", .0)]
436 RecursiveMacro(String),
437 #[error("The macro \"{}\" is not defined", .0)]
439 MissingMacro(String),
440 #[error("The string \"{}\" begins a macro without ending it", .0)]
442 IncompleteMacro(String),
443 #[error("The partial macro insertion of \"{}\" in \"{}\" must be a string", .0, .1)]
445 PartialMacro(String, String),
446 #[error("The macro insertion in the header \"{}\" must be a string", .0)]
448 HeaderMacro(String),
449 #[error("The macro insertion in the footer \"{}\" must be a string", .0)]
451 FooterMacro(String),
452}