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<String>,
190}
191
192#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
194pub enum DefaultType {
195 Required,
197 Optional,
200 Default(SerializationModel),
203}
204
205#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
207#[serde(untagged)]
208pub enum SerializationModel {
209 Map(HashMap<String, SerializationModel>),
211 Array(Vec<SerializationModel>),
213 Value(String),
215}
216
217pub(crate) fn expand_macros<'a>(
227 value: &SerializationModel,
228 macros: &'a HashMap<String, SerializationModel>,
229 used_macros: &mut HashSet<&'a str>,
230) -> Result<SerializationModel, Error> {
231 return match value {
232 SerializationModel::Map(value) => value
233 .iter()
234 .map(|(k, v)| match expand_macros(v, macros, used_macros) {
235 Ok(value) => Ok((k.clone(), value)),
236 Err(error) => Err(error.add_field(k)),
237 })
238 .collect::<Result<HashMap<_, _>, _>>()
239 .map(SerializationModel::Map),
240 SerializationModel::Array(value) => value
241 .iter()
242 .enumerate()
243 .map(|(i, v)| match expand_macros(v, macros, used_macros) {
244 Ok(value) => Ok(value),
245 Err(error) => Err(error.add_element(i)),
246 })
247 .collect::<Result<Vec<_>, _>>()
248 .map(SerializationModel::Array),
249 SerializationModel::Value(value) => {
250 if value.starts_with('$')
252 && value.ends_with('$')
253 && value.len() > 2
254 && value.chars().filter(|c| *c == '$').count() == 2
255 {
256 let macro_name = &value[1..value.len() - 1];
257
258 if used_macros.contains(macro_name) {
260 return Err(Error {
261 location: "".to_string(),
262 error: ErrorCore::RecursiveMacro(macro_name.to_string()),
263 });
264 }
265
266 return if let Some((macro_key, macro_value)) = macros.get_key_value(macro_name) {
268 used_macros.insert(macro_key.as_str());
269 let expanded_macro = expand_macros(macro_value, macros, used_macros);
270 used_macros.remove(macro_key.as_str());
271 match expanded_macro {
272 Ok(value) => Ok(value),
273 Err(error) => Err(error.add_macro(macro_name)),
274 }
275 } else {
276 Err(Error {
277 location: "".to_string(),
278 error: ErrorCore::MissingMacro(macro_name.to_string()),
279 })
280 };
281 }
282
283 let mut expanded_string = String::new();
285 let mut current_index = 0;
286 while current_index < value.len() {
287 if let Some(start_index) = value[current_index..].find('$') {
289 let start_index = start_index + current_index + 1;
290 expanded_string.push_str(&value[current_index..start_index - 1]);
291
292 if start_index < value.len() && &value[start_index..start_index + 1] == "$" {
294 expanded_string.push('$');
295 current_index = start_index + 1;
296 continue;
297 }
298
299 if let Some(end_index) = value[start_index..].find('$') {
301 let end_index = end_index + start_index;
302 let macro_name = &value[start_index..end_index];
303
304 if used_macros.contains(macro_name) {
306 return Err(Error {
307 location: "".to_string(),
308 error: ErrorCore::RecursiveMacro(macro_name.to_string()),
309 });
310 }
311
312 if let Some((macro_key, macro_value)) = macros.get_key_value(macro_name) {
313 used_macros.insert(macro_key.as_str());
315 let expanded_macro = expand_macros(macro_value, macros, used_macros);
316 used_macros.remove(macro_key.as_str());
317 match expanded_macro {
318 Ok(ok_value) => match ok_value {
319 SerializationModel::Value(value) => {
320 expanded_string.push_str(&value);
321 }
322 _ => {
323 return Err(Error {
324 location: "".to_string(),
325 error: ErrorCore::PartialMacro(
326 macro_name.to_string(),
327 value.clone(),
328 ),
329 });
330 }
331 },
332 Err(error) => {
333 return Err(error.add_macro(macro_name));
334 }
335 }
336 } else {
337 return Err(Error {
338 location: "".to_string(),
339 error: ErrorCore::MissingMacro(macro_name.to_string()),
340 });
341 }
342
343 current_index = end_index + 1;
344 } else {
345 return Err(Error {
346 location: "".to_string(),
347 error: ErrorCore::IncompleteMacro(value.clone()),
348 });
349 }
350 } else {
351 expanded_string.push_str(&value[current_index..]);
352 break;
353 }
354 }
355
356 Ok(SerializationModel::Value(expanded_string))
357 }
358 };
359}
360
361#[derive(Debug, Clone)]
364pub struct Error {
365 pub location: String,
367 pub error: ErrorCore,
369}
370
371impl Error {
372 fn add_field(self, base: &str) -> Error {
378 let location = format!(".{}{}", base, self.location);
379
380 return Error {
381 location,
382 error: self.error,
383 };
384 }
385
386 fn add_element(self, index: usize) -> Error {
392 let location = format!("[{}]{}", index, self.location);
393
394 return Error {
395 location,
396 error: self.error,
397 };
398 }
399
400 fn add_macro(self, index: &str) -> Error {
406 let location = format!("[{}]{}", index, self.location);
407
408 return Error {
409 location,
410 error: self.error,
411 };
412 }
413}
414
415impl fmt::Display for Error {
416 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
417 return write!(f, "{}: {}", self.location, self.error);
418 }
419}
420
421#[derive(thiserror::Error, Debug, Clone)]
423pub enum ErrorCore {
424 #[error("The macro \"{}\" is used recursively", .0)]
426 RecursiveMacro(String),
427 #[error("The macro \"{}\" is not defined", .0)]
429 MissingMacro(String),
430 #[error("The string \"{}\" begins a macro without ending it", .0)]
432 IncompleteMacro(String),
433 #[error("The partial macro insertion of \"{}\" in \"{}\" must be a string", .0, .1)]
435 PartialMacro(String, String),
436}