1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use crate::*;
use codegen::{Function, Variant};
use serde::Deserialize;
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
struct Category {
caption: String,
description: String,
uid: u8,
}
pub fn generate_categories(paths: &DirPaths) -> Result<(), Box<dyn Error>> {
let mut output_scope = Scope::new();
let categories_file = read_file_to_value(&format!("{}categories.json", paths.schema_path))?;
let categories_description: String = categories_file
.get("description")
.unwrap_or(&Value::String("".to_string()))
.as_str()
.unwrap()
.to_string();
output_scope.writeln("//! OCSF Category data");
output_scope.writeln("//!".to_string());
output_scope.writeln(format!("//! {categories_description}"));
output_scope.add_generation_timestamp_comment();
let enum_name = "Category";
let mut category_enum = codegen::Enum::new(enum_name);
category_enum.vis("pub").doc(&categories_description);
let mut category_to_u8 = Function::new("from");
category_to_u8.arg("input", enum_name).ret("u8");
category_to_u8.line("match input {");
let mut u8_to_category = Function::new("try_from");
u8_to_category
.arg("input", "u8")
.ret("Result<Self, String>");
u8_to_category.line("let res = match input {");
if let Some(attributes) = categories_file.get("attributes") {
if let Some(attributes_object) = attributes.as_object() {
attributes_object.into_iter().for_each(|(key, value)| {
let category: Category = serde_json::from_value(value.clone()).unwrap();
let variant_name = collapsed_title_case(key);
let variant_docstring = vec![
format!("/// {}", category.description),
"///".to_string(),
format!("/// `uid={}`", category.uid),
];
let variant = Variant::new(&variant_name)
.annotation(variant_docstring.join("\n"))
.to_owned();
category_enum.push_variant(variant);
category_to_u8.line(format!(
"{}::{} => {},",
enum_name, variant_name, category.uid
));
u8_to_category.line(format!(
"{} => {}::{},",
category.uid, enum_name, variant_name
));
})
}
}
category_to_u8.line("}");
let mut category_to_u8_impl = codegen::Impl::new("u8");
category_to_u8_impl.impl_trait(format!("From<{enum_name}>"));
category_to_u8_impl.push_fn(category_to_u8);
u8_to_category.line("_ => return Err(format!(\"Invalid value specified: {input}\")),\n");
u8_to_category.line("};");
u8_to_category.line("Ok(res)");
let mut u8_to_category_impl = codegen::Impl::new(enum_name);
u8_to_category_impl
.impl_trait("TryFrom<u8>")
.associate_type("Error", "String");
u8_to_category_impl.push_fn(u8_to_category);
output_scope.push_enum(category_enum.to_owned());
output_scope.push_impl(category_to_u8_impl.to_owned());
output_scope.push_impl(u8_to_category_impl.to_owned());
write_source_file(
&format!("{}src/categories.rs", paths.destination_path),
&output_scope.to_string(),
)
}