1use std::collections::HashMap;
8use std::fmt;
9
10use crate::mib::{Oid, ParseOidError};
11use crate::types::{BaseType, Diagnostic, Kind, Severity};
12
13use super::capability::CapabilityData;
14use super::compliance::ComplianceData;
15use super::group::GroupData;
16use super::handle::{
17 Capability, Compliance, Group, HandleIter, Module, Node, Notification, Object, Type,
18};
19use super::module::ModuleData;
20use super::node::{NodeData, OidTree};
21use super::notification::NotificationData;
22use super::object::ObjectData;
23use super::raw::RawMib;
24use super::symbol::Symbol;
25use super::typedef::TypeData;
26use super::types::*;
27
28pub struct Mib {
38 pub(crate) tree: OidTree,
39
40 pub(crate) objects: Vec<ObjectData>,
42 pub(crate) types: Vec<TypeData>,
43 pub(crate) notifications: Vec<NotificationData>,
44 pub(crate) groups: Vec<GroupData>,
45 pub(crate) compliances: Vec<ComplianceData>,
46 pub(crate) capabilities: Vec<CapabilityData>,
47 pub(crate) modules: Vec<ModuleData>,
48
49 pub(crate) module_by_name: HashMap<String, ModuleId>,
51 pub(crate) name_to_nodes: HashMap<String, Vec<NodeId>>,
52 pub(crate) type_by_name: HashMap<String, TypeId>,
53
54 pub(crate) node_count: usize,
55 pub(crate) diagnostics: Vec<Diagnostic>,
56 pub(crate) unresolved: Vec<UnresolvedRef>,
57}
58
59impl Mib {
60 pub(crate) fn new() -> Self {
61 Self {
62 tree: OidTree::new(),
63 objects: Vec::new(),
64 types: Vec::new(),
65 notifications: Vec::new(),
66 groups: Vec::new(),
67 compliances: Vec::new(),
68 capabilities: Vec::new(),
69 modules: Vec::new(),
70 module_by_name: HashMap::new(),
71 name_to_nodes: HashMap::new(),
72 type_by_name: HashMap::new(),
73 node_count: 0,
74 diagnostics: Vec::new(),
75 unresolved: Vec::new(),
76 }
77 }
78
79 pub(crate) fn tree(&self) -> &OidTree {
82 &self.tree
83 }
84
85 pub fn raw(&self) -> RawMib<'_> {
90 RawMib::new(self)
91 }
92
93 pub(crate) fn node_data(&self, id: NodeId) -> &NodeData {
94 self.tree.get(id)
95 }
96
97 #[must_use]
102 pub fn root_node(&self) -> Node<'_> {
103 Node::new(self, self.tree.root())
104 }
105
106 pub(crate) fn object_data(&self, id: ObjectId) -> &ObjectData {
109 &self.objects[id.0 as usize]
110 }
111
112 #[must_use]
113 pub(crate) fn type_data(&self, id: TypeId) -> &TypeData {
114 &self.types[id.0 as usize]
115 }
116
117 pub(crate) fn notification_data(&self, id: NotificationId) -> &NotificationData {
118 &self.notifications[id.0 as usize]
119 }
120
121 pub(crate) fn group_data(&self, id: GroupId) -> &GroupData {
122 &self.groups[id.0 as usize]
123 }
124
125 pub(crate) fn compliance_data(&self, id: ComplianceId) -> &ComplianceData {
126 &self.compliances[id.0 as usize]
127 }
128
129 pub(crate) fn capability_data(&self, id: CapabilityId) -> &CapabilityData {
130 &self.capabilities[id.0 as usize]
131 }
132
133 pub(crate) fn module_data(&self, id: ModuleId) -> &ModuleData {
134 &self.modules[id.0 as usize]
135 }
136
137 pub(crate) fn object_mut(&mut self, id: ObjectId) -> &mut ObjectData {
140 &mut self.objects[id.0 as usize]
141 }
142
143 pub(crate) fn type_mut(&mut self, id: TypeId) -> &mut TypeData {
144 &mut self.types[id.0 as usize]
145 }
146
147 pub(crate) fn module_mut(&mut self, id: ModuleId) -> &mut ModuleData {
148 &mut self.modules[id.0 as usize]
149 }
150
151 fn find_in_nodes<T>(&self, name: &str, get: impl Fn(&NodeData) -> Option<T>) -> Option<T> {
156 for &id in self.name_to_nodes.get(name)? {
157 if let Some(val) = get(self.tree.get(id)) {
158 return Some(val);
159 }
160 }
161 None
162 }
163
164 #[must_use]
169 pub fn nodes_by_name(&self, name: &str) -> &[NodeId] {
170 self.name_to_nodes
171 .get(name)
172 .map(|v| v.as_slice())
173 .unwrap_or(&[])
174 }
175
176 #[must_use]
182 pub fn node_by_name(&self, name: &str) -> Option<NodeId> {
183 let nodes = self.name_to_nodes.get(name)?;
184 for &id in nodes {
185 if self.tree.get(id).object.is_some() {
186 return Some(id);
187 }
188 }
189 for &id in nodes {
190 if self.tree.get(id).notification.is_some() {
191 return Some(id);
192 }
193 }
194 nodes.first().copied()
195 }
196
197 #[must_use]
199 pub fn object_by_name(&self, name: &str) -> Option<ObjectId> {
200 self.find_in_nodes(name, |n| n.object)
201 }
202
203 #[must_use]
205 pub fn object(&self, name: &str) -> Option<Object<'_>> {
206 self.object_by_name(name).map(|id| Object::new(self, id))
207 }
208
209 #[must_use]
211 pub fn type_by_name(&self, name: &str) -> Option<TypeId> {
212 self.type_by_name.get(name).copied()
213 }
214
215 #[must_use]
217 pub fn r#type(&self, name: &str) -> Option<Type<'_>> {
218 self.type_by_name(name).map(|id| Type::new(self, id))
219 }
220
221 #[must_use]
223 pub fn notification_by_name(&self, name: &str) -> Option<NotificationId> {
224 self.find_in_nodes(name, |n| n.notification)
225 }
226
227 #[must_use]
229 pub fn notification(&self, name: &str) -> Option<Notification<'_>> {
230 self.notification_by_name(name)
231 .map(|id| Notification::new(self, id))
232 }
233
234 #[must_use]
236 pub fn group_by_name(&self, name: &str) -> Option<GroupId> {
237 self.find_in_nodes(name, |n| n.group)
238 }
239
240 #[must_use]
242 pub fn group(&self, name: &str) -> Option<Group<'_>> {
243 self.group_by_name(name).map(|id| Group::new(self, id))
244 }
245
246 #[must_use]
248 pub fn compliance_by_name(&self, name: &str) -> Option<ComplianceId> {
249 self.find_in_nodes(name, |n| n.compliance)
250 }
251
252 #[must_use]
254 pub fn compliance(&self, name: &str) -> Option<Compliance<'_>> {
255 self.compliance_by_name(name)
256 .map(|id| Compliance::new(self, id))
257 }
258
259 #[must_use]
261 pub fn capability_by_name(&self, name: &str) -> Option<CapabilityId> {
262 self.find_in_nodes(name, |n| n.capability)
263 }
264
265 #[must_use]
267 pub fn capability(&self, name: &str) -> Option<Capability<'_>> {
268 self.capability_by_name(name)
269 .map(|id| Capability::new(self, id))
270 }
271
272 #[must_use]
274 pub fn module_by_name(&self, name: &str) -> Option<ModuleId> {
275 self.module_by_name.get(name).copied()
276 }
277
278 #[must_use]
280 pub fn module(&self, name: &str) -> Option<Module<'_>> {
281 self.module_by_name(name).map(|id| Module::new(self, id))
282 }
283
284 #[must_use]
289 pub fn symbol_by_name(&self, name: &str) -> Option<Symbol> {
290 if let Some(nodes) = self.name_to_nodes.get(name) {
291 let mut notification = None;
292 let mut group = None;
293 let mut compliance = None;
294 let mut capability = None;
295 let mut node = None;
296
297 for &id in nodes {
298 let entry = self.tree.get(id);
299 node.get_or_insert(id);
300 if let Some(object) = entry.object {
301 return Some(Symbol::Object(object));
302 }
303 notification = notification.or(entry.notification);
304 group = group.or(entry.group);
305 compliance = compliance.or(entry.compliance);
306 capability = capability.or(entry.capability);
307 }
308
309 if let Some(id) = notification {
310 return Some(Symbol::Notification(id));
311 }
312 if let Some(id) = group {
313 return Some(Symbol::Group(id));
314 }
315 if let Some(id) = compliance {
316 return Some(Symbol::Compliance(id));
317 }
318 if let Some(id) = capability {
319 return Some(Symbol::Capability(id));
320 }
321 if let Some(id) = node {
322 return Some(Symbol::Node(id));
323 }
324 }
325 if let Some(&id) = self.type_by_name.get(name) {
326 return Some(Symbol::Type(id));
327 }
328 None
329 }
330
331 #[must_use]
337 pub fn node_by_oid(&self, oid: &Oid) -> Option<NodeId> {
338 let (id, exact) = self.tree.walk_oid(self.tree.root(), oid);
339 if exact { Some(id) } else { None }
340 }
341
342 #[must_use]
344 pub fn node(&self, name: &str) -> Option<Node<'_>> {
345 self.node_by_name(name).map(|id| Node::new(self, id))
346 }
347
348 #[must_use]
353 pub fn exact_node_by_oid(&self, oid: &Oid) -> Option<Node<'_>> {
354 self.node_by_oid(oid).map(|id| Node::new(self, id))
355 }
356
357 #[must_use]
359 pub fn longest_prefix_by_oid(&self, oid: &Oid) -> NodeId {
360 self.tree.longest_prefix(oid)
361 }
362
363 #[must_use]
371 pub fn lookup_oid(&self, oid: &Oid) -> Node<'_> {
372 Node::new(self, self.longest_prefix_by_oid(oid))
373 }
374
375 #[must_use]
404 pub fn lookup_instance(&self, oid: &Oid) -> OidLookup<'_> {
405 let id = self.longest_prefix_by_oid(oid);
406 let node_oid = self.tree.oid_of(id);
407 let suffix = oid[node_oid.len()..].to_vec();
408 OidLookup {
409 node: Node::new(self, id),
410 suffix,
411 }
412 }
413
414 pub fn subtree(&self, id: NodeId) -> super::node::SubtreeIter<'_> {
416 self.tree.subtree(id)
417 }
418
419 #[must_use]
421 pub fn longest_prefix_from(&self, start: NodeId, oid: &Oid) -> NodeId {
422 self.tree.longest_prefix_from(start, oid)
423 }
424
425 pub(crate) fn effective_module(&self, id: NodeId) -> Option<ModuleId> {
426 self.tree.get(id).module
427 }
428
429 pub fn format_oid(&self, oid: &Oid) -> String {
435 if oid.is_empty() {
436 return String::new();
437 }
438 let lookup = self.lookup_instance(oid);
439 let matched = self.tree.get(lookup.node.id);
440 if matched.name.is_empty() {
441 return oid.to_string();
442 }
443
444 let mut result = String::new();
445 if let Some(mod_id) = self.effective_module(lookup.node.id) {
446 result.push_str(&self.modules[mod_id.0 as usize].name);
447 result.push_str("::");
448 }
449 result.push_str(&matched.name);
450 for arc in lookup.suffix() {
451 result.push('.');
452 result.push_str(&arc.to_string());
453 }
454 result
455 }
456
457 pub fn resolve_node(&self, query: &str) -> Option<Node<'_>> {
464 self.resolve(query).map(|id| Node::new(self, id))
465 }
466
467 pub(crate) fn resolve(&self, query: &str) -> Option<NodeId> {
468 let q = query.strip_prefix('.').unwrap_or(query);
470 if q.starts_with(|c: char| c.is_ascii_digit()) {
471 let oid: Oid = q.parse().ok()?;
472 return Some(self.longest_prefix_by_oid(&oid));
473 }
474
475 self.resolve_oid(query)
476 .ok()
477 .map(|oid| self.longest_prefix_by_oid(&oid))
478 }
479
480 pub fn resolve_oid(&self, query: &str) -> Result<Oid, ResolveOidError> {
490 if query.is_empty() {
491 return Err(ResolveOidError::EmptyQuery);
492 }
493
494 let q = query.strip_prefix('.').unwrap_or(query);
495 if q.starts_with(|c: char| c.is_ascii_digit()) {
496 return q.parse::<Oid>().map_err(ResolveOidError::InvalidOid);
497 }
498
499 if let Some((mod_name, rest)) = query.split_once("::") {
501 let (name, suffix) = split_name_suffix(rest);
502 let mod_id = self
503 .module_by_name
504 .get(mod_name)
505 .ok_or_else(|| ResolveOidError::ModuleNotFound(mod_name.to_string()))?;
506 let node_id = self.modules[mod_id.0 as usize]
507 .node_by_name(name)
508 .ok_or_else(|| ResolveOidError::QualifiedNodeNotFound {
509 module: mod_name.to_string(),
510 name: name.to_string(),
511 })?;
512 let base = self.tree.oid_of(node_id).clone();
513 return append_suffix(base, suffix);
514 }
515
516 let (name, suffix) = split_name_suffix(query);
518 let node_id = self
519 .node_by_name(name)
520 .ok_or_else(|| ResolveOidError::NodeNotFound(name.to_string()))?;
521 let base = self.tree.oid_of(node_id).clone();
522 append_suffix(base, suffix)
523 }
524
525 pub fn all_symbols(&self) -> Vec<Symbol> {
529 let mut result = Vec::new();
530 for module in &self.modules {
531 result.extend(module.definitions());
532 }
533 result
534 }
535
536 pub fn available_symbols(&self, mod_id: ModuleId) -> Vec<Symbol> {
542 let module = self.module_data(mod_id);
543 let mut result = Vec::new();
544 let mut seen = std::collections::HashSet::new();
545
546 for sym in module.definitions() {
548 seen.insert(sym.name(self).to_string());
549 result.push(sym);
550 }
551
552 for imp in &module.imports {
554 for is in &imp.symbols {
555 if seen.contains(&is.name) {
556 continue;
557 }
558 seen.insert(is.name.clone());
559 let Some(&source_mod_id) = module.resolved_imports.get(&is.name) else {
560 continue;
561 };
562 let source = self.module_data(source_mod_id);
563 if let Some(sym) = source.symbol(&is.name) {
564 result.push(sym);
565 }
566 }
567 }
568
569 result
570 }
571
572 pub fn modules(&self) -> HandleIter<'_, Module<'_>, impl Iterator<Item = ModuleId>> {
580 HandleIter::new(
581 self,
582 (0..self.modules.len()).map(|i| ModuleId::new(i as u32)),
583 )
584 }
585
586 pub fn user_modules(&self) -> impl Iterator<Item = Module<'_>> + '_ {
591 self.modules
592 .iter()
593 .enumerate()
594 .filter(|(_, m)| !m.is_base())
595 .map(|(i, _)| Module::new(self, ModuleId::new(i as u32)))
596 }
597
598 pub fn objects(&self) -> HandleIter<'_, Object<'_>, impl Iterator<Item = ObjectId>> {
603 HandleIter::new(
604 self,
605 (0..self.objects.len()).map(|i| ObjectId::new(i as u32)),
606 )
607 }
608
609 pub fn types(&self) -> HandleIter<'_, Type<'_>, impl Iterator<Item = TypeId>> {
614 HandleIter::new(self, (0..self.types.len()).map(|i| TypeId::new(i as u32)))
615 }
616
617 pub fn nodes(&self) -> HandleIter<'_, Node<'_>, impl Iterator<Item = NodeId>> {
622 HandleIter::new(self, self.tree.all_nodes())
623 }
624
625 pub fn notifications(
627 &self,
628 ) -> HandleIter<'_, Notification<'_>, impl Iterator<Item = NotificationId>> {
629 HandleIter::new(
630 self,
631 (0..self.notifications.len()).map(|i| NotificationId::new(i as u32)),
632 )
633 }
634
635 pub fn groups(&self) -> HandleIter<'_, Group<'_>, impl Iterator<Item = GroupId>> {
637 HandleIter::new(self, (0..self.groups.len()).map(|i| GroupId::new(i as u32)))
638 }
639
640 pub fn compliances(
642 &self,
643 ) -> HandleIter<'_, Compliance<'_>, impl Iterator<Item = ComplianceId>> {
644 HandleIter::new(
645 self,
646 (0..self.compliances.len()).map(|i| ComplianceId::new(i as u32)),
647 )
648 }
649
650 pub fn capabilities(
652 &self,
653 ) -> HandleIter<'_, Capability<'_>, impl Iterator<Item = CapabilityId>> {
654 HandleIter::new(
655 self,
656 (0..self.capabilities.len()).map(|i| CapabilityId::new(i as u32)),
657 )
658 }
659
660 pub fn node_by_id(&self, id: NodeId) -> Node<'_> {
662 Node::new(self, id)
663 }
664
665 pub fn object_by_id(&self, id: ObjectId) -> Object<'_> {
667 Object::new(self, id)
668 }
669
670 pub fn type_by_id(&self, id: TypeId) -> Type<'_> {
672 Type::new(self, id)
673 }
674
675 pub fn module_by_id(&self, id: ModuleId) -> Module<'_> {
677 Module::new(self, id)
678 }
679
680 pub fn notification_by_id(&self, id: NotificationId) -> Notification<'_> {
682 Notification::new(self, id)
683 }
684
685 pub fn group_by_id(&self, id: GroupId) -> Group<'_> {
687 Group::new(self, id)
688 }
689
690 pub fn compliance_by_id(&self, id: ComplianceId) -> Compliance<'_> {
692 Compliance::new(self, id)
693 }
694
695 pub fn capability_by_id(&self, id: CapabilityId) -> Capability<'_> {
697 Capability::new(self, id)
698 }
699
700 pub(crate) fn modules_slice(&self) -> &[ModuleData] {
701 &self.modules
702 }
703
704 pub(crate) fn objects_slice(&self) -> &[ObjectData] {
705 &self.objects
706 }
707
708 pub(crate) fn types_slice(&self) -> &[TypeData] {
709 &self.types
710 }
711
712 pub(crate) fn notifications_slice(&self) -> &[NotificationData] {
713 &self.notifications
714 }
715
716 pub(crate) fn groups_slice(&self) -> &[GroupData] {
717 &self.groups
718 }
719
720 pub(crate) fn compliances_slice(&self) -> &[ComplianceData] {
721 &self.compliances
722 }
723
724 pub(crate) fn capabilities_slice(&self) -> &[CapabilityData] {
725 &self.capabilities
726 }
727
728 pub fn modules_defining(&self, name: &str) -> Vec<ModuleId> {
732 self.modules
733 .iter()
734 .enumerate()
735 .filter(|(_, m)| !m.is_base && m.defines_symbol(name))
736 .map(|(i, _)| ModuleId::new(i as u32))
737 .collect()
738 }
739
740 pub fn modules_importing(&self, name: &str) -> Vec<ModuleId> {
744 self.modules
745 .iter()
746 .enumerate()
747 .filter(|(_, m)| !m.is_base && m.imports_symbol(name))
748 .map(|(i, _)| ModuleId::new(i as u32))
749 .collect()
750 }
751
752 pub fn objects_by_kind(&self, kind: Kind) -> Vec<ObjectId> {
754 self.objects
755 .iter()
756 .enumerate()
757 .filter(|(_, obj)| {
758 obj.entity
759 .node
760 .is_some_and(|id| self.tree.get(id).kind == kind)
761 })
762 .map(|(i, _)| ObjectId::new(i as u32))
763 .collect()
764 }
765
766 pub fn tables(&self) -> impl Iterator<Item = Object<'_>> + '_ {
768 self.objects_with_kind(Kind::Table)
769 }
770
771 pub fn scalars(&self) -> impl Iterator<Item = Object<'_>> + '_ {
773 self.objects_with_kind(Kind::Scalar)
774 }
775
776 pub fn columns(&self) -> impl Iterator<Item = Object<'_>> + '_ {
778 self.objects_with_kind(Kind::Column)
779 }
780
781 pub fn rows(&self) -> impl Iterator<Item = Object<'_>> + '_ {
783 self.objects_with_kind(Kind::Row)
784 }
785
786 pub fn objects_by_type_name(&self, type_name: &str) -> Vec<ObjectId> {
788 self.objects
789 .iter()
790 .enumerate()
791 .filter(|(_, obj)| {
792 obj.typ
793 .is_some_and(|id| self.types[id.0 as usize].name == type_name)
794 })
795 .map(|(i, _)| ObjectId::new(i as u32))
796 .collect()
797 }
798
799 pub fn objects_by_base_type(&self, base: BaseType) -> Vec<ObjectId> {
801 self.objects
802 .iter()
803 .enumerate()
804 .filter(|(_, obj)| {
805 obj.typ
806 .is_some_and(|id| self.types[id.0 as usize].effective_base(&self.types) == base)
807 })
808 .map(|(i, _)| ObjectId::new(i as u32))
809 .collect()
810 }
811
812 pub fn object_table(&self, id: ObjectId) -> Option<ObjectId> {
818 let node_id = self.object_data(id).node()?;
819 let node = self.tree.get(node_id);
820 match node.kind {
821 Kind::Table => Some(id),
822 Kind::Row => {
823 let parent = self.tree.get(node.parent?);
824 parent.object
825 }
826 Kind::Column => {
827 let parent = self.tree.get(node.parent?);
828 let grandparent = self.tree.get(parent.parent?);
829 grandparent.object
830 }
831 _ => None,
832 }
833 }
834
835 pub fn object_row(&self, id: ObjectId) -> Option<ObjectId> {
840 let node_id = self.object_data(id).node()?;
841 let node = self.tree.get(node_id);
842 match node.kind {
843 Kind::Table => {
844 for &child_id in node.children.values() {
845 let child = self.tree.get(child_id);
846 if child.kind == Kind::Row {
847 return child.object;
848 }
849 }
850 None
851 }
852 Kind::Row => Some(id),
853 Kind::Column => {
854 let parent = self.tree.get(node.parent?);
855 parent.object
856 }
857 _ => None,
858 }
859 }
860
861 pub fn object_columns(&self, id: ObjectId) -> Vec<ObjectId> {
865 let Some(node_id) = self.object_data(id).node() else {
866 return Vec::new();
867 };
868 let node = self.tree.get(node_id);
869 let row_node = match node.kind {
870 Kind::Table => {
871 let mut found = None;
872 for &child_id in node.children.values() {
873 if self.tree.get(child_id).kind == Kind::Row {
874 found = Some(child_id);
875 break;
876 }
877 }
878 match found {
879 Some(id) => self.tree.get(id),
880 None => return Vec::new(),
881 }
882 }
883 Kind::Row => node,
884 _ => return Vec::new(),
885 };
886 let mut cols = Vec::new();
887 for &child_id in row_node.children.values() {
888 let child = self.tree.get(child_id);
889 if let Some(obj_id) = child.object.filter(|_| child.kind == Kind::Column) {
890 cols.push(obj_id);
891 }
892 }
893 cols
894 }
895
896 pub fn effective_indexes(&self, id: ObjectId) -> Vec<IndexEntry> {
901 let mut visited = Vec::new();
902 self.effective_indexes_inner(id, &mut visited)
903 }
904
905 pub(crate) fn effective_indexes_source(&self, id: ObjectId) -> Option<ObjectId> {
906 let mut visited = Vec::new();
907 self.effective_indexes_source_inner(id, &mut visited)
908 }
909
910 fn effective_indexes_inner(
911 &self,
912 id: ObjectId,
913 visited: &mut Vec<ObjectId>,
914 ) -> Vec<IndexEntry> {
915 let obj = self.object_data(id);
916 let Some(node_id) = obj.node() else {
917 return Vec::new();
918 };
919 let kind = self.tree.get(node_id).kind;
920 if kind == Kind::Column {
921 if let Some(row_id) = self.object_row(id) {
922 return self.effective_indexes_inner(row_id, visited);
923 }
924 return Vec::new();
925 }
926 if kind != Kind::Row {
927 return Vec::new();
928 }
929 if !obj.index.is_empty() {
930 return obj.index.clone();
931 }
932 if let Some(aug_id) = obj.augments {
933 if visited.contains(&id) {
934 return Vec::new();
935 }
936 visited.push(id);
937 return self.effective_indexes_inner(aug_id, visited);
938 }
939 Vec::new()
940 }
941
942 fn effective_indexes_source_inner(
943 &self,
944 id: ObjectId,
945 visited: &mut Vec<ObjectId>,
946 ) -> Option<ObjectId> {
947 let obj = self.object_data(id);
948 let node_id = obj.node()?;
949 let kind = self.tree.get(node_id).kind;
950 if kind == Kind::Column {
951 let row_id = self.object_row(id)?;
952 return self.effective_indexes_source_inner(row_id, visited);
953 }
954 if kind != Kind::Row {
955 return None;
956 }
957 if !obj.index.is_empty() {
958 return Some(id);
959 }
960 let aug_id = obj.augments?;
961 if visited.contains(&id) {
962 return None;
963 }
964 visited.push(id);
965 self.effective_indexes_source_inner(aug_id, visited)
966 }
967
968 pub fn is_table(&self, id: ObjectId) -> bool {
972 self.object_kind(id) == Kind::Table
973 }
974
975 pub fn is_row(&self, id: ObjectId) -> bool {
977 self.object_kind(id) == Kind::Row
978 }
979
980 pub fn is_column(&self, id: ObjectId) -> bool {
982 self.object_kind(id) == Kind::Column
983 }
984
985 pub fn is_scalar(&self, id: ObjectId) -> bool {
987 self.object_kind(id) == Kind::Scalar
988 }
989
990 pub fn is_index(&self, id: ObjectId) -> bool {
992 if self.object_kind(id) != Kind::Column {
993 return false;
994 }
995 self.effective_indexes(id)
996 .iter()
997 .any(|idx| idx.object == Some(id))
998 }
999
1000 fn objects_with_kind(&self, kind: Kind) -> impl Iterator<Item = Object<'_>> + '_ {
1001 self.objects.iter().enumerate().filter_map(move |(i, obj)| {
1002 let node_id = obj.entity.node?;
1003 if self.tree.get(node_id).kind == kind {
1004 Some(Object::new(self, ObjectId::new(i as u32)))
1005 } else {
1006 None
1007 }
1008 })
1009 }
1010
1011 fn object_kind(&self, id: ObjectId) -> Kind {
1012 match self.object_data(id).node() {
1013 Some(node_id) => self.tree.get(node_id).kind,
1014 None => Kind::Unknown,
1015 }
1016 }
1017
1018 pub fn node_count(&self) -> usize {
1022 self.node_count
1023 }
1024
1025 pub fn diagnostics(&self) -> &[Diagnostic] {
1027 &self.diagnostics
1028 }
1029
1030 pub fn unresolved(&self) -> &[UnresolvedRef] {
1032 &self.unresolved
1033 }
1034
1035 pub fn has_errors(&self) -> bool {
1037 self.diagnostics
1038 .iter()
1039 .any(|d| d.severity.at_least(Severity::Error))
1040 }
1041
1042 pub(crate) fn set_node_count(&mut self, n: usize) {
1045 self.node_count = n;
1046 }
1047
1048 pub(crate) fn add_module(&mut self, data: ModuleData) -> ModuleId {
1049 let id = ModuleId::new(self.modules.len() as u32);
1050 if !data.name.is_empty() {
1051 self.module_by_name.insert(data.name.clone(), id);
1052 }
1053 self.modules.push(data);
1054 id
1055 }
1056
1057 pub(crate) fn add_object(&mut self, data: ObjectData) -> ObjectId {
1058 let id = ObjectId::new(self.objects.len() as u32);
1059 self.objects.push(data);
1060 id
1061 }
1062
1063 pub(crate) fn add_type(&mut self, data: TypeData) -> TypeId {
1064 let id = TypeId::new(self.types.len() as u32);
1065 if !data.name.is_empty() && !self.type_by_name.contains_key(&data.name) {
1066 self.type_by_name.insert(data.name.clone(), id);
1067 }
1068 self.types.push(data);
1069 id
1070 }
1071
1072 pub(crate) fn add_notification(&mut self, data: NotificationData) -> NotificationId {
1073 let id = NotificationId::new(self.notifications.len() as u32);
1074 self.notifications.push(data);
1075 id
1076 }
1077
1078 pub(crate) fn add_group(&mut self, data: GroupData) -> GroupId {
1079 let id = GroupId::new(self.groups.len() as u32);
1080 self.groups.push(data);
1081 id
1082 }
1083
1084 pub(crate) fn add_compliance(&mut self, data: ComplianceData) -> ComplianceId {
1085 let id = ComplianceId::new(self.compliances.len() as u32);
1086 self.compliances.push(data);
1087 id
1088 }
1089
1090 pub(crate) fn add_capability(&mut self, data: CapabilityData) -> CapabilityId {
1091 let id = CapabilityId::new(self.capabilities.len() as u32);
1092 self.capabilities.push(data);
1093 id
1094 }
1095
1096 pub(crate) fn register_node(&mut self, name: &str, id: NodeId) {
1097 if !name.is_empty() {
1098 self.name_to_nodes
1099 .entry(name.to_string())
1100 .or_default()
1101 .push(id);
1102 }
1103 }
1104
1105 pub(crate) fn add_diagnostic(&mut self, d: Diagnostic) {
1106 self.diagnostics.push(d);
1107 }
1108
1109 pub(crate) fn add_unresolved(&mut self, r: UnresolvedRef) {
1110 self.unresolved.push(r);
1111 }
1112}
1113
1114impl Default for Mib {
1115 fn default() -> Self {
1116 Self::new()
1117 }
1118}
1119
1120impl fmt::Debug for Mib {
1121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1122 f.debug_struct("Mib")
1123 .field("modules", &self.modules.len())
1124 .field("objects", &self.objects.len())
1125 .field("types", &self.types.len())
1126 .field("notifications", &self.notifications.len())
1127 .field("node_count", &self.node_count)
1128 .finish()
1129 }
1130}
1131
1132fn split_name_suffix(s: &str) -> (&str, &str) {
1133 match s.find('.') {
1134 Some(i) => (&s[..i], &s[i..]),
1135 None => (s, ""),
1136 }
1137}
1138
1139fn append_suffix(base: Oid, suffix: &str) -> Result<Oid, ResolveOidError> {
1140 if suffix.is_empty() {
1141 return Ok(base);
1142 }
1143 let extra: Oid = suffix
1144 .parse()
1145 .map_err(|source| ResolveOidError::InvalidSuffix {
1146 suffix: suffix.to_string(),
1147 source,
1148 })?;
1149 Ok(base.child_oid(&extra))
1150}
1151
1152pub struct OidLookup<'a> {
1155 node: Node<'a>,
1156 suffix: Vec<u32>,
1157}
1158
1159impl<'a> OidLookup<'a> {
1160 #[must_use]
1162 pub fn node(&self) -> Node<'a> {
1163 self.node
1164 }
1165
1166 #[must_use]
1171 pub fn suffix(&self) -> &[u32] {
1172 &self.suffix
1173 }
1174
1175 #[must_use]
1185 pub fn decode_indexes(&self) -> Vec<super::index::DecodedIndex> {
1186 let Some(obj) = self.node.object() else {
1187 return Vec::new();
1188 };
1189 let mut indexes = obj.effective_indexes().peekable();
1190 if indexes.peek().is_none() {
1191 return Vec::new();
1192 }
1193 super::index::decode_suffix(indexes, &self.suffix)
1194 }
1195}
1196
1197#[derive(Debug, Clone, thiserror::Error)]
1199pub enum ResolveOidError {
1200 #[error("empty query")]
1202 EmptyQuery,
1203 #[error("invalid OID: {0}")]
1205 InvalidOid(#[source] ParseOidError),
1206 #[error("module not found: {0}")]
1208 ModuleNotFound(String),
1209 #[error("node not found: {0}")]
1211 NodeNotFound(String),
1212 #[error("node not found: {module}::{name}")]
1214 QualifiedNodeNotFound {
1215 module: String,
1217 name: String,
1219 },
1220 #[error("invalid instance suffix {suffix:?}: {source}")]
1222 InvalidSuffix {
1223 suffix: String,
1225 #[source]
1226 source: ParseOidError,
1227 },
1228}
1229
1230impl Oid {
1232 fn child_oid(&self, suffix: &Oid) -> Oid {
1233 let mut arcs = Vec::with_capacity(self.len() + suffix.len());
1234 arcs.extend_from_slice(self);
1235 arcs.extend_from_slice(suffix);
1236 Oid::from(arcs)
1237 }
1238}
1239
1240#[cfg(test)]
1241mod tests {
1242 use super::*;
1243 use crate::mib::module::ModuleData;
1244 use crate::mib::object::ObjectData;
1245 use crate::mib::typedef::TypeData;
1246
1247 fn make_mib_with_two_modules() -> Mib {
1248 let mut mib = Mib::new();
1249
1250 let mut mod_a = ModuleData::new("MOD-A".to_string());
1252 let obj_data = ObjectData::new("objA".to_string());
1253 let obj_id = mib.add_object(obj_data);
1254 mod_a.add_object("objA", obj_id);
1255
1256 let type_data = TypeData::new("TypeA".to_string());
1257 let type_id = mib.add_type(type_data);
1258 mod_a.add_type("TypeA", type_id);
1259 let _mod_a_id = mib.add_module(mod_a);
1260
1261 let mut mod_b = ModuleData::new("MOD-B".to_string());
1263 let obj_data2 = ObjectData::new("objB".to_string());
1264 let obj_id2 = mib.add_object(obj_data2);
1265 mod_b.add_object("objB", obj_id2);
1266 let _mod_b_id = mib.add_module(mod_b);
1267
1268 mib
1269 }
1270
1271 #[test]
1272 fn all_symbols_across_modules() {
1273 let mib = make_mib_with_two_modules();
1274 let syms = mib.all_symbols();
1275 let names: Vec<&str> = syms.iter().map(|s| s.name(&mib)).collect();
1276
1277 assert!(names.contains(&"objA"));
1278 assert!(names.contains(&"TypeA"));
1279 assert!(names.contains(&"objB"));
1280 assert_eq!(names.len(), 3);
1281 }
1282
1283 #[test]
1284 fn available_symbols_own_only() {
1285 let mib = make_mib_with_two_modules();
1286 let mod_a_id = *mib.module_by_name.get("MOD-A").unwrap();
1287
1288 let syms = mib.available_symbols(mod_a_id);
1289 let names: Vec<&str> = syms.iter().map(|s| s.name(&mib)).collect();
1290
1291 assert!(names.contains(&"objA"));
1292 assert!(names.contains(&"TypeA"));
1293 assert!(!names.contains(&"objB"));
1294 }
1295
1296 #[test]
1297 fn available_symbols_with_imports() {
1298 let mut mib = Mib::new();
1299
1300 let mut source_mod = ModuleData::new("SOURCE-MIB".to_string());
1302 let obj_data = ObjectData::new("srcObj".to_string());
1303 let obj_id = mib.add_object(obj_data);
1304 source_mod.add_object("srcObj", obj_id);
1305 let source_mod_id = mib.add_module(source_mod);
1306
1307 let mut consumer = ModuleData::new("CONSUMER-MIB".to_string());
1309 let own_type = TypeData::new("OwnType".to_string());
1310 let own_type_id = mib.add_type(own_type);
1311 consumer.add_type("OwnType", own_type_id);
1312 consumer.imports.push(crate::mib::types::Import {
1313 module: "SOURCE-MIB".to_string(),
1314 symbols: vec![crate::mib::types::ImportSymbol {
1315 name: "srcObj".to_string(),
1316 span: crate::types::Span::SYNTHETIC,
1317 }],
1318 });
1319 consumer
1320 .resolved_imports
1321 .insert("srcObj".to_string(), source_mod_id);
1322 let consumer_id = mib.add_module(consumer);
1323
1324 let syms = mib.available_symbols(consumer_id);
1325 let names: Vec<&str> = syms.iter().map(|s| s.name(&mib)).collect();
1326
1327 assert_eq!(names, vec!["OwnType", "srcObj"]);
1328 }
1329
1330 #[test]
1331 fn available_symbols_dedup_own_over_import() {
1332 let mut mib = Mib::new();
1333
1334 let mut source_mod = ModuleData::new("SOURCE-MIB".to_string());
1336 let src_type = TypeData::new("shared".to_string());
1337 let src_type_id = mib.add_type(src_type);
1338 source_mod.add_type("shared", src_type_id);
1339 let source_mod_id = mib.add_module(source_mod);
1340
1341 let mut consumer = ModuleData::new("CONSUMER-MIB".to_string());
1343 let own_type = TypeData::new("shared".to_string());
1344 let own_type_id = mib.add_type(own_type);
1345 consumer.add_type("shared", own_type_id);
1346 consumer.imports.push(crate::mib::types::Import {
1347 module: "SOURCE-MIB".to_string(),
1348 symbols: vec![crate::mib::types::ImportSymbol {
1349 name: "shared".to_string(),
1350 span: crate::types::Span::SYNTHETIC,
1351 }],
1352 });
1353 consumer
1354 .resolved_imports
1355 .insert("shared".to_string(), source_mod_id);
1356 let consumer_id = mib.add_module(consumer);
1357
1358 let syms = mib.available_symbols(consumer_id);
1359 let names: Vec<&str> = syms.iter().map(|s| s.name(&mib)).collect();
1360
1361 assert_eq!(names, vec!["shared"]);
1363 }
1364}