netgauze_ipfix_code_generator/xml_parsers/
sub_registries.rs1use crate::{
17 xml_parsers::xml_common::*, InformationElementSubRegistry, ReasonCodeNestedRegistry,
18 SubRegistryType, ValueNameDescRegistry, Xref,
19};
20
21use regex::Regex;
22use roxmltree::Node;
23
24const MAX_WORDS_NAME: usize = 10;
25
26pub trait SubRegistry {
28 fn name(&self) -> &str;
29 fn description(&self) -> &str;
30 fn comments(&self) -> &Option<String>;
31 fn parameters(&self) -> &Option<String>;
32 fn xrefs(&self) -> &Vec<Xref>;
33}
34
35impl SubRegistry for ValueNameDescRegistry {
36 fn name(&self) -> &str {
37 &self.name
38 }
39
40 fn description(&self) -> &str {
41 &self.description
42 }
43
44 fn comments(&self) -> &Option<String> {
45 &self.comments
46 }
47
48 fn parameters(&self) -> &Option<String> {
49 &self.parameters
50 }
51
52 fn xrefs(&self) -> &Vec<Xref> {
53 &self.xrefs
54 }
55}
56
57impl SubRegistry for ReasonCodeNestedRegistry {
58 fn name(&self) -> &str {
59 &self.name
60 }
61
62 fn description(&self) -> &str {
63 &self.description
64 }
65
66 fn comments(&self) -> &Option<String> {
67 &self.comments
68 }
69
70 fn parameters(&self) -> &Option<String> {
71 &self.parameters
72 }
73
74 fn xrefs(&self) -> &Vec<Xref> {
75 &self.xrefs
76 }
77}
78
79pub fn parse_subregistry(
82 node: &Node<'_, '_>,
83 registry_type: SubRegistryType,
84) -> (u16, Vec<InformationElementSubRegistry>) {
85 match registry_type {
86 SubRegistryType::ValueNameDescRegistry => {
87 let (ie_id, reg) = parse_val_name_desc_u8_registry(node);
88 let ie_subreg: Vec<InformationElementSubRegistry> = reg
89 .into_iter()
90 .map(InformationElementSubRegistry::ValueNameDescRegistry)
91 .collect();
92 (ie_id, ie_subreg)
93 }
94 SubRegistryType::ReasonCodeNestedRegistry => {
95 let (ie_id, reg) = parse_reason_code_nested_u8_registry_2bit(node);
96 let ie_subreg: Vec<InformationElementSubRegistry> = reg
97 .into_iter()
98 .map(InformationElementSubRegistry::ReasonCodeNestedRegistry)
99 .collect();
100 (ie_id, ie_subreg)
101 }
102 }
103}
104
105pub fn parse_val_name_desc_u8_registry(node: &Node<'_, '_>) -> (u16, Vec<ValueNameDescRegistry>) {
110 let mut ret = Vec::new();
111
112 let children = node
113 .children()
114 .filter(|x| x.tag_name() == (IANA_NAMESPACE, "record").into())
115 .collect::<Vec<_>>();
116
117 let title = get_string_child(node, (IANA_NAMESPACE, "title").into()).unwrap_or_default();
118
119 let ie_id_regex = Regex::new(r"Value (\d+)").unwrap();
120 let ie_id = ie_id_regex
121 .captures(&title)
122 .and_then(|captures| captures.get(1))
123 .and_then(|capture| capture.as_str().parse().ok())
124 .unwrap_or(0);
125
126 for child in &children {
127 let value = get_string_child(child, (IANA_NAMESPACE, "value").into()).map(|x| {
128 if let Some(hex_value) = x.strip_prefix("0x") {
129 u8::from_str_radix(hex_value, 16)
130 } else if let Some(bin_value) = x.strip_prefix("0b") {
131 u8::from_str_radix(bin_value, 2)
132 } else if let Some(bin_value) = x.strip_suffix('b') {
133 u8::from_str_radix(bin_value, 2)
134 } else {
135 x.parse::<u8>()
136 }
137 });
138
139 let name_parsed = get_string_child(child, (IANA_NAMESPACE, "name").into());
140
141 if Some(true)
143 == name_parsed
144 .as_ref()
145 .map(|x| x.as_str() == UNASSIGNED || x.contains(EXPERIMENTATION))
146 {
147 continue;
148 }
149
150 let description_parsed = parse_simple_description_string(child);
151 if Some(true)
152 == description_parsed
153 .as_ref()
154 .map(|x| x.as_str() == UNASSIGNED || x.contains(EXPERIMENTATION))
155 {
156 continue;
157 }
158
159 let mut name: String;
162 let description: String;
163 if let Some(Ok(value)) = value {
164 if value == u8::MAX {
165 continue;
167 }
168
169 if let Some(name_parsed) = name_parsed {
170 (_, name) = xml_string_to_enum_type(&name_parsed);
171 if let Some(desc_parsed) = description_parsed {
172 description = desc_parsed;
173 } else {
174 description = name_parsed;
175 }
176 } else if let Some(mut desc_parsed) = description_parsed {
177 description = desc_parsed.clone();
178
179 let desc_words_amount: usize;
180 (desc_words_amount, desc_parsed) = xml_string_to_enum_type(&desc_parsed);
181
182 if desc_words_amount < MAX_WORDS_NAME {
183 name = desc_parsed;
184 } else {
185 name = format!("Value{value}");
186 }
187 } else {
188 log::info!("Skipping sub-registry: missing both name and description!");
189 continue;
190 }
191
192 if name == *RESERVED || name == *PRIVATE {
194 name = format!("{name}{value}");
195 }
196
197 let comments = get_string_child(child, (IANA_NAMESPACE, "comments").into());
198 let parameters = get_string_child(child, (IANA_NAMESPACE, "parameters").into());
199 let xrefs = parse_xref(child);
200
201 ret.push(ValueNameDescRegistry {
202 value,
203 name,
204 description,
205 comments,
206 parameters,
207 xrefs,
208 });
209 }
210 }
211
212 (ie_id, ret)
213}
214
215pub fn parse_reason_code_nested_u8_registry_2bit(
218 node: &Node<'_, '_>,
219) -> (u16, Vec<ReasonCodeNestedRegistry>) {
220 let (ie_id, subreg) = parse_val_name_desc_u8_registry(node);
221
222 let ret: Vec<ReasonCodeNestedRegistry> = subreg
223 .iter()
224 .map(|subreg| {
225 let val_bin_str = format!("{:02b}", subreg.value);
226 let reason_code_pattern = format!(r".*-{val_bin_str}b");
227 let reason_code_reg_pattern = Regex::new(&reason_code_pattern).unwrap();
228 let reason_code_node = find_node_by_regex(node, &reason_code_reg_pattern).unwrap();
229 ReasonCodeNestedRegistry {
230 value: subreg.value << 6,
231 name: SubRegistry::name(subreg).to_string(),
232 description: SubRegistry::description(subreg).to_string(),
233 comments: SubRegistry::comments(subreg).to_owned(),
234 parameters: SubRegistry::parameters(subreg).to_owned(),
235 xrefs: SubRegistry::xrefs(subreg).to_owned(),
236 reason_code_reg: {
237 let (_, reg) = parse_val_name_desc_u8_registry(&reason_code_node);
238 let reg: Vec<InformationElementSubRegistry> = reg
239 .into_iter()
240 .map(InformationElementSubRegistry::ValueNameDescRegistry)
241 .collect();
242 reg
243 },
244 }
245 })
246 .collect();
247
248 (ie_id, ret)
249}