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