1use std::collections::BTreeMap;
13use std::sync::OnceLock;
14
15use crate::mib::Oid;
16use crate::types::{Kind, Span, Status};
17
18use super::types::*;
19
20#[derive(Debug)]
27pub struct NodeData {
28 pub(crate) arc: u32,
29 pub(crate) name: String,
30 pub(crate) description: String,
31 pub(crate) reference: String,
32 pub(crate) status: Option<Status>,
33 pub(crate) kind: Kind,
34 pub(crate) span: Span,
35 pub(crate) parent: Option<NodeId>,
36 pub(crate) children: BTreeMap<u32, NodeId>,
37 pub(crate) module: Option<ModuleId>,
38 pub(crate) object: Option<ObjectId>,
39 pub(crate) notification: Option<NotificationId>,
40 pub(crate) group: Option<GroupId>,
41 pub(crate) compliance: Option<ComplianceId>,
42 pub(crate) capability: Option<CapabilityId>,
43 pub(crate) oid_cache: OnceLock<Oid>,
44}
45
46impl NodeData {
47 pub(crate) fn new(arc: u32, parent: Option<NodeId>) -> Self {
48 Self {
49 arc,
50 name: String::new(),
51 description: String::new(),
52 reference: String::new(),
53 status: None,
54 kind: Kind::Internal,
55 span: Span::SYNTHETIC,
56 parent,
57 children: BTreeMap::new(),
58 module: None,
59 object: None,
60 notification: None,
61 group: None,
62 compliance: None,
63 capability: None,
64 oid_cache: OnceLock::new(),
65 }
66 }
67
68 pub(crate) fn root() -> Self {
69 Self::new(0, None)
70 }
71}
72
73impl NodeData {
74 pub fn arc(&self) -> u32 {
76 self.arc
77 }
78
79 pub fn name(&self) -> &str {
81 &self.name
82 }
83
84 pub fn description(&self) -> &str {
86 &self.description
87 }
88
89 pub fn reference(&self) -> &str {
91 &self.reference
92 }
93
94 pub fn status(&self) -> Option<Status> {
96 self.status
97 }
98
99 pub fn kind(&self) -> Kind {
101 self.kind
102 }
103
104 pub fn span(&self) -> Span {
106 self.span
107 }
108
109 pub fn parent(&self) -> Option<NodeId> {
111 self.parent
112 }
113
114 pub fn children(&self) -> &BTreeMap<u32, NodeId> {
116 &self.children
117 }
118
119 pub fn module(&self) -> Option<ModuleId> {
121 self.module
122 }
123
124 pub fn object(&self) -> Option<ObjectId> {
126 self.object
127 }
128
129 pub fn notification(&self) -> Option<NotificationId> {
131 self.notification
132 }
133
134 pub fn group(&self) -> Option<GroupId> {
136 self.group
137 }
138
139 pub fn compliance(&self) -> Option<ComplianceId> {
141 self.compliance
142 }
143
144 pub fn capability(&self) -> Option<CapabilityId> {
146 self.capability
147 }
148
149 pub fn is_root(&self) -> bool {
151 self.parent.is_none()
152 }
153}
154
155#[derive(Debug)]
161pub struct OidTree {
162 nodes: Vec<NodeData>,
163 root: NodeId,
164}
165
166impl OidTree {
167 pub fn new() -> Self {
169 Self {
170 nodes: vec![NodeData::root()],
171 root: NodeId::new(0),
172 }
173 }
174
175 pub fn root(&self) -> NodeId {
177 self.root
178 }
179
180 pub fn len(&self) -> usize {
182 self.nodes.len()
183 }
184
185 pub fn is_empty(&self) -> bool {
187 self.nodes.is_empty()
188 }
189
190 pub fn get(&self, id: NodeId) -> &NodeData {
196 &self.nodes[id.0 as usize]
197 }
198
199 fn alloc(&mut self, data: NodeData) -> NodeId {
200 let id = NodeId::new(self.nodes.len() as u32);
201 self.nodes.push(data);
202 id
203 }
204
205 pub(crate) fn get_or_create_child(&mut self, parent: NodeId, arc: u32) -> NodeId {
207 if let Some(&child_id) = self.nodes[parent.0 as usize].children.get(&arc) {
208 return child_id;
209 }
210 let child_id = self.alloc(NodeData::new(arc, Some(parent)));
211 self.nodes[parent.0 as usize].children.insert(arc, child_id);
212 child_id
213 }
214
215 pub(crate) fn set_name(&mut self, id: NodeId, name: String) {
216 self.nodes[id.0 as usize].name = name;
217 }
218
219 pub(crate) fn set_kind(&mut self, id: NodeId, kind: Kind) {
220 self.nodes[id.0 as usize].kind = kind;
221 }
222
223 pub(crate) fn set_status(&mut self, id: NodeId, status: Status) {
224 self.nodes[id.0 as usize].status = Some(status);
225 }
226
227 pub(crate) fn set_description(&mut self, id: NodeId, desc: String) {
228 self.nodes[id.0 as usize].description = desc;
229 }
230
231 pub(crate) fn set_reference(&mut self, id: NodeId, reference: String) {
232 self.nodes[id.0 as usize].reference = reference;
233 }
234
235 pub(crate) fn set_span(&mut self, id: NodeId, span: Span) {
236 self.nodes[id.0 as usize].span = span;
237 }
238
239 pub(crate) fn set_module(&mut self, id: NodeId, module: ModuleId) {
240 self.nodes[id.0 as usize].module = Some(module);
241 }
242
243 pub(crate) fn attach_object(&mut self, id: NodeId, obj: ObjectId) {
244 self.nodes[id.0 as usize].object = Some(obj);
245 }
246
247 pub(crate) fn attach_notification(&mut self, id: NodeId, notif: NotificationId) {
248 self.nodes[id.0 as usize].notification = Some(notif);
249 }
250
251 pub(crate) fn attach_group(&mut self, id: NodeId, group: GroupId) {
252 self.nodes[id.0 as usize].group = Some(group);
253 }
254
255 pub(crate) fn attach_compliance(&mut self, id: NodeId, compliance: ComplianceId) {
256 self.nodes[id.0 as usize].compliance = Some(compliance);
257 }
258
259 pub(crate) fn attach_capability(&mut self, id: NodeId, cap: CapabilityId) {
260 self.nodes[id.0 as usize].capability = Some(cap);
261 }
262
263 pub fn walk_oid(&self, start: NodeId, oid: &Oid) -> (NodeId, bool) {
268 let mut current = start;
269 for &arc in oid.iter() {
270 match self.nodes[current.0 as usize].children.get(&arc) {
271 Some(&child) => current = child,
272 None => return (current, false),
273 }
274 }
275 (current, true)
276 }
277
278 fn compute_oid(&self, id: NodeId) -> Oid {
279 let node = &self.nodes[id.0 as usize];
280 if node.parent.is_none() {
281 return Oid::default();
282 }
283 let mut arcs = Vec::new();
284 let mut current = id;
285 loop {
286 let n = &self.nodes[current.0 as usize];
287 match n.parent {
288 Some(parent) => {
289 arcs.push(n.arc);
290 current = parent;
291 }
292 None => break,
293 }
294 }
295 arcs.reverse();
296 Oid::from(arcs)
297 }
298
299 pub fn oid_of(&self, id: NodeId) -> &Oid {
301 self.nodes[id.0 as usize]
302 .oid_cache
303 .get_or_init(|| self.compute_oid(id))
304 }
305
306 pub fn subtree(&self, start: NodeId) -> SubtreeIter<'_> {
308 SubtreeIter {
309 tree: self,
310 stack: vec![start],
311 }
312 }
313
314 pub fn all_nodes(&self) -> SubtreeIter<'_> {
316 let root = &self.nodes[self.root.0 as usize];
317 let stack: Vec<NodeId> = root.children.values().rev().copied().collect();
318 SubtreeIter { tree: self, stack }
319 }
320
321 pub fn longest_prefix(&self, oid: &Oid) -> NodeId {
323 let (matched, _) = self.walk_oid(self.root, oid);
324 matched
325 }
326
327 pub fn longest_prefix_from(&self, start: NodeId, oid: &Oid) -> NodeId {
329 let (matched, _) = self.walk_oid(start, oid);
330 matched
331 }
332}
333
334impl Default for OidTree {
335 fn default() -> Self {
336 Self::new()
337 }
338}
339
340pub struct SubtreeIter<'a> {
342 tree: &'a OidTree,
343 stack: Vec<NodeId>,
344}
345
346impl<'a> Iterator for SubtreeIter<'a> {
347 type Item = NodeId;
348
349 fn next(&mut self) -> Option<NodeId> {
350 let id = self.stack.pop()?;
351 let node = &self.tree.nodes[id.0 as usize];
352 for (_, &child_id) in node.children.iter().rev() {
354 self.stack.push(child_id);
355 }
356 Some(id)
357 }
358}
359
360#[cfg(test)]
361mod tests {
362 use super::*;
363
364 #[test]
365 fn tree_construction() {
366 let mut tree = OidTree::new();
367 let root = tree.root();
368
369 let iso = tree.get_or_create_child(root, 1);
370 tree.set_name(iso, "iso".into());
371
372 let org = tree.get_or_create_child(iso, 3);
373 tree.set_name(org, "org".into());
374
375 let dod = tree.get_or_create_child(org, 6);
376 tree.set_name(dod, "dod".into());
377
378 assert_eq!(tree.len(), 4); assert_eq!(tree.get(iso).name, "iso");
380 assert_eq!(tree.get(org).name, "org");
381 assert_eq!(tree.get(dod).name, "dod");
382
383 let oid = tree.oid_of(dod);
384 assert_eq!(&**oid, &[1, 3, 6]);
385 }
386
387 #[test]
388 fn get_or_create_idempotent() {
389 let mut tree = OidTree::new();
390 let root = tree.root();
391
392 let a = tree.get_or_create_child(root, 1);
393 let b = tree.get_or_create_child(root, 1);
394 assert_eq!(a, b);
395 assert_eq!(tree.len(), 2);
396 }
397
398 #[test]
399 fn walk_oid_exact() {
400 let mut tree = OidTree::new();
401 let root = tree.root();
402 let a = tree.get_or_create_child(root, 1);
403 let b = tree.get_or_create_child(a, 3);
404 let c = tree.get_or_create_child(b, 6);
405
406 let oid: Oid = "1.3.6".parse().unwrap();
407 let (matched, exact) = tree.walk_oid(root, &oid);
408 assert!(exact);
409 assert_eq!(matched, c);
410 }
411
412 #[test]
413 fn walk_oid_partial() {
414 let mut tree = OidTree::new();
415 let root = tree.root();
416 let a = tree.get_or_create_child(root, 1);
417 let _b = tree.get_or_create_child(a, 3);
418
419 let oid: Oid = "1.3.6.1".parse().unwrap();
420 let (_, exact) = tree.walk_oid(root, &oid);
421 assert!(!exact);
422 }
423
424 #[test]
425 fn subtree_iteration() {
426 let mut tree = OidTree::new();
427 let root = tree.root();
428 let a = tree.get_or_create_child(root, 1);
429 let b = tree.get_or_create_child(a, 2);
430 let c = tree.get_or_create_child(a, 3);
431
432 let nodes: Vec<NodeId> = tree.subtree(a).collect();
433 assert_eq!(nodes, vec![a, b, c]);
434 }
435
436 #[test]
437 fn all_nodes_excludes_root() {
438 let mut tree = OidTree::new();
439 let root = tree.root();
440 let a = tree.get_or_create_child(root, 1);
441 let b = tree.get_or_create_child(root, 2);
442
443 let nodes: Vec<NodeId> = tree.all_nodes().collect();
444 assert_eq!(nodes, vec![a, b]);
445 }
446
447 #[test]
448 fn oid_caching() {
449 let mut tree = OidTree::new();
450 let root = tree.root();
451 let a = tree.get_or_create_child(root, 1);
452 let b = tree.get_or_create_child(a, 3);
453
454 let oid1 = tree.oid_of(b);
455 let oid2 = tree.oid_of(b);
456 assert!(std::ptr::eq(oid1, oid2));
457 }
458
459 #[test]
460 fn root_oid_is_empty() {
461 let tree = OidTree::new();
462 let root = tree.root();
463 assert!(tree.oid_of(root).is_empty());
464 }
465
466 #[test]
467 fn longest_prefix_from_node() {
468 let mut tree = OidTree::new();
469 let root = tree.root();
470 let a = tree.get_or_create_child(root, 1);
471 let b = tree.get_or_create_child(a, 3);
472 let c = tree.get_or_create_child(b, 6);
473
474 let matched = tree.longest_prefix_from(a, &"3.6".parse().unwrap());
476 assert_eq!(matched, c);
477
478 let matched = tree.longest_prefix_from(a, &"3.6.99".parse().unwrap());
480 assert_eq!(matched, c);
481
482 let matched = tree.longest_prefix_from(b, &"99".parse().unwrap());
484 assert_eq!(matched, b);
485 }
486
487 #[test]
488 fn is_root() {
489 let mut tree = OidTree::new();
490 let root = tree.root();
491 let child = tree.get_or_create_child(root, 1);
492
493 assert!(tree.get(root).is_root());
494 assert!(!tree.get(child).is_root());
495 }
496}