1use std::collections::{HashMap, HashSet};
10
11use crate::mib::Oid;
12use crate::source::{SourceId, SourceRange};
13use crate::types::{Language, Status};
14
15use super::navigation::SemanticSpanIndex;
16use super::symbol::Symbol;
17use super::types::*;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25pub enum ModuleIdentityKind {
26 ModuleIdentity,
28 ObjectIdentity,
30 ObjectIdentifier,
32}
33
34#[derive(Debug, Clone)]
40pub struct ModuleIdentityData {
41 pub(crate) name: String,
42 pub(crate) kind: ModuleIdentityKind,
43 pub(crate) oid: Oid,
44 pub(crate) status: Option<Status>,
45 pub(crate) description: String,
46 pub(crate) reference: String,
47 pub(crate) last_updated: String,
48 pub(crate) organization: String,
49 pub(crate) contact_info: String,
50 pub(crate) revisions: Vec<Revision>,
51 pub(crate) oid_refs: Vec<OidRef>,
52 pub(crate) range: SourceRange,
53}
54
55impl ModuleIdentityData {
56 pub fn name(&self) -> &str {
58 &self.name
59 }
60
61 pub fn kind(&self) -> ModuleIdentityKind {
63 self.kind
64 }
65
66 pub fn oid(&self) -> &Oid {
68 &self.oid
69 }
70
71 pub fn status(&self) -> Option<Status> {
73 self.status
74 }
75
76 pub fn description(&self) -> &str {
78 &self.description
79 }
80
81 pub fn reference(&self) -> &str {
83 &self.reference
84 }
85
86 pub fn last_updated(&self) -> &str {
88 &self.last_updated
89 }
90
91 pub fn organization(&self) -> &str {
93 &self.organization
94 }
95
96 pub fn contact_info(&self) -> &str {
98 &self.contact_info
99 }
100
101 pub fn revisions(&self) -> &[Revision] {
103 &self.revisions
104 }
105
106 pub fn oid_refs(&self) -> &[OidRef] {
108 &self.oid_refs
109 }
110
111 pub fn declared_oid_parent(&self) -> Option<&OidRef> {
113 let parent = self.oid.parent()?;
114 self.oid_refs
115 .iter()
116 .rev()
117 .find(|reference| reference.oid() == Some(&parent))
118 }
119
120 pub fn declared_oid_parent_name(&self) -> &str {
123 self.declared_oid_parent()
124 .map_or("", |reference| reference.name.as_str())
125 }
126
127 pub fn range(&self) -> SourceRange {
129 self.range
130 }
131}
132
133pub struct ModuleData {
139 pub(crate) name: String,
140 pub(crate) language: Language,
141 pub(crate) source_id: Option<SourceId>,
142 pub(crate) is_base: bool,
143 pub(crate) oid: Option<Oid>,
144 pub(crate) organization: String,
145 pub(crate) contact_info: String,
146 pub(crate) description: String,
147 pub(crate) last_updated: String,
148 pub(crate) revisions: Vec<Revision>,
149 pub(crate) imports: Vec<Import>,
150 pub(crate) identities: Vec<ModuleIdentityData>,
151
152 pub(crate) objects: Vec<ObjectId>,
153 pub(crate) types: Vec<TypeId>,
154 pub(crate) notifications: Vec<NotificationId>,
155 pub(crate) groups: Vec<GroupId>,
156 pub(crate) compliances: Vec<ComplianceId>,
157 pub(crate) capabilities: Vec<CapabilityId>,
158 pub(crate) nodes: Vec<NodeId>,
159
160 pub(crate) used_import_names: HashSet<String>,
161 pub(crate) resolved_imports: HashMap<String, ModuleId>,
162 pub(crate) import_resolutions: HashMap<String, ImportResolution>,
163 pub(crate) semantic_spans: SemanticSpanIndex,
164
165 pub(crate) objects_by_name: HashMap<String, ObjectId>,
166 pub(crate) types_by_name: HashMap<String, TypeId>,
167 pub(crate) notifications_by_name: HashMap<String, NotificationId>,
168 pub(crate) groups_by_name: HashMap<String, GroupId>,
169 pub(crate) compliances_by_name: HashMap<String, ComplianceId>,
170 pub(crate) capabilities_by_name: HashMap<String, CapabilityId>,
171 pub(crate) nodes_by_name: HashMap<String, NodeId>,
172}
173
174impl ModuleData {
175 pub(crate) fn new(name: String) -> Self {
176 Self {
177 name,
178 language: Language::Unknown,
179 source_id: None,
180 is_base: false,
181 oid: None,
182 organization: String::new(),
183 contact_info: String::new(),
184 description: String::new(),
185 last_updated: String::new(),
186 revisions: Vec::new(),
187 imports: Vec::new(),
188 identities: Vec::new(),
189 objects: Vec::new(),
190 types: Vec::new(),
191 notifications: Vec::new(),
192 groups: Vec::new(),
193 compliances: Vec::new(),
194 capabilities: Vec::new(),
195 nodes: Vec::new(),
196 used_import_names: HashSet::new(),
197 resolved_imports: HashMap::new(),
198 import_resolutions: HashMap::new(),
199 semantic_spans: SemanticSpanIndex::default(),
200 objects_by_name: HashMap::new(),
201 types_by_name: HashMap::new(),
202 notifications_by_name: HashMap::new(),
203 groups_by_name: HashMap::new(),
204 compliances_by_name: HashMap::new(),
205 capabilities_by_name: HashMap::new(),
206 nodes_by_name: HashMap::new(),
207 }
208 }
209
210 pub fn name(&self) -> &str {
212 &self.name
213 }
214
215 pub fn language(&self) -> Language {
217 self.language
218 }
219
220 pub fn source_id(&self) -> Option<SourceId> {
222 self.source_id
223 }
224
225 pub fn is_base(&self) -> bool {
229 self.is_base
230 }
231
232 pub fn oid(&self) -> Option<&Oid> {
234 self.oid.as_ref()
235 }
236
237 pub fn organization(&self) -> &str {
239 &self.organization
240 }
241
242 pub fn contact_info(&self) -> &str {
244 &self.contact_info
245 }
246
247 pub fn description(&self) -> &str {
249 &self.description
250 }
251
252 pub fn last_updated(&self) -> &str {
254 &self.last_updated
255 }
256
257 pub fn revisions(&self) -> &[Revision] {
259 &self.revisions
260 }
261
262 pub fn imports(&self) -> &[Import] {
264 &self.imports
265 }
266
267 pub fn identities(&self) -> &[ModuleIdentityData] {
272 &self.identities
273 }
274
275 pub fn objects(&self) -> &[ObjectId] {
277 &self.objects
278 }
279
280 pub fn types(&self) -> &[TypeId] {
282 &self.types
283 }
284
285 pub fn notifications(&self) -> &[NotificationId] {
287 &self.notifications
288 }
289
290 pub fn groups(&self) -> &[GroupId] {
292 &self.groups
293 }
294
295 pub fn compliances(&self) -> &[ComplianceId] {
297 &self.compliances
298 }
299
300 pub fn capabilities(&self) -> &[CapabilityId] {
302 &self.capabilities
303 }
304
305 pub fn nodes(&self) -> &[NodeId] {
307 &self.nodes
308 }
309
310 pub fn object_by_name(&self, name: &str) -> Option<ObjectId> {
312 self.objects_by_name.get(name).copied()
313 }
314
315 pub fn type_by_name(&self, name: &str) -> Option<TypeId> {
317 self.types_by_name.get(name).copied()
318 }
319
320 pub fn notification_by_name(&self, name: &str) -> Option<NotificationId> {
322 self.notifications_by_name.get(name).copied()
323 }
324
325 pub fn group_by_name(&self, name: &str) -> Option<GroupId> {
327 self.groups_by_name.get(name).copied()
328 }
329
330 pub fn compliance_by_name(&self, name: &str) -> Option<ComplianceId> {
332 self.compliances_by_name.get(name).copied()
333 }
334
335 pub fn capability_by_name(&self, name: &str) -> Option<CapabilityId> {
337 self.capabilities_by_name.get(name).copied()
338 }
339
340 pub fn node_by_name(&self, name: &str) -> Option<NodeId> {
342 self.nodes_by_name.get(name).copied()
343 }
344
345 pub fn symbol(&self, name: &str) -> Option<Symbol> {
348 if let Some(&id) = self.objects_by_name.get(name) {
349 return Some(Symbol::Object(id));
350 }
351 if let Some(&id) = self.types_by_name.get(name) {
352 return Some(Symbol::Type(id));
353 }
354 if let Some(&id) = self.notifications_by_name.get(name) {
355 return Some(Symbol::Notification(id));
356 }
357 if let Some(&id) = self.groups_by_name.get(name) {
358 return Some(Symbol::Group(id));
359 }
360 if let Some(&id) = self.compliances_by_name.get(name) {
361 return Some(Symbol::Compliance(id));
362 }
363 if let Some(&id) = self.capabilities_by_name.get(name) {
364 return Some(Symbol::Capability(id));
365 }
366 if let Some(&id) = self.nodes_by_name.get(name) {
367 return Some(Symbol::Node(id));
368 }
369 None
370 }
371
372 pub fn symbols(&self, name: &str) -> Vec<Symbol> {
377 let mut symbols = Vec::new();
378 if let Some(&id) = self.objects_by_name.get(name) {
379 symbols.push(Symbol::Object(id));
380 }
381 if let Some(&id) = self.notifications_by_name.get(name) {
382 symbols.push(Symbol::Notification(id));
383 }
384 if let Some(&id) = self.groups_by_name.get(name) {
385 symbols.push(Symbol::Group(id));
386 }
387 if let Some(&id) = self.compliances_by_name.get(name) {
388 symbols.push(Symbol::Compliance(id));
389 }
390 if let Some(&id) = self.capabilities_by_name.get(name) {
391 symbols.push(Symbol::Capability(id));
392 }
393 if symbols.is_empty()
394 && let Some(&id) = self.nodes_by_name.get(name)
395 {
396 symbols.push(Symbol::Node(id));
397 }
398 if let Some(&id) = self.types_by_name.get(name) {
399 symbols.push(Symbol::Type(id));
400 }
401 symbols
402 }
403
404 pub fn defines_symbol(&self, name: &str) -> bool {
406 self.symbol(name).is_some()
407 }
408
409 pub fn imports_symbol(&self, name: &str) -> bool {
411 self.imports
412 .iter()
413 .any(|imp| imp.symbols.iter().any(|s| s.name == name))
414 }
415
416 pub fn is_import_used(&self, name: &str) -> bool {
418 self.used_import_names.contains(name)
419 }
420
421 pub fn import_source(&self, name: &str) -> Option<ModuleId> {
423 self.resolved_imports.get(name).copied()
424 }
425
426 pub fn import_resolution(&self, name: &str) -> Option<&ImportResolution> {
428 self.import_resolutions.get(name)
429 }
430
431 pub(crate) fn add_object(&mut self, name: impl Into<String>, id: ObjectId) {
434 self.objects.push(id);
435 self.objects_by_name.entry(name.into()).or_insert(id);
436 }
437
438 pub(crate) fn add_type(&mut self, name: impl Into<String>, id: TypeId) {
439 self.types.push(id);
440 self.types_by_name.entry(name.into()).or_insert(id);
441 }
442
443 pub(crate) fn add_notification(&mut self, name: impl Into<String>, id: NotificationId) {
444 self.notifications.push(id);
445 self.notifications_by_name.entry(name.into()).or_insert(id);
446 }
447
448 pub(crate) fn add_group(&mut self, name: impl Into<String>, id: GroupId) {
449 self.groups.push(id);
450 self.groups_by_name.entry(name.into()).or_insert(id);
451 }
452
453 pub(crate) fn add_compliance(&mut self, name: impl Into<String>, id: ComplianceId) {
454 self.compliances.push(id);
455 self.compliances_by_name.entry(name.into()).or_insert(id);
456 }
457
458 pub(crate) fn add_capability(&mut self, name: impl Into<String>, id: CapabilityId) {
459 self.capabilities.push(id);
460 self.capabilities_by_name.entry(name.into()).or_insert(id);
461 }
462
463 pub(crate) fn add_node(&mut self, name: impl Into<String>, id: NodeId) {
464 self.nodes.push(id);
465 self.nodes_by_name.entry(name.into()).or_insert(id);
466 }
467
468 pub(crate) fn add_identity(&mut self, identity: ModuleIdentityData) {
469 self.identities.push(identity);
470 }
471
472 pub fn definitions(&self) -> impl Iterator<Item = Symbol> + '_ {
478 let covered_node_ids: HashSet<NodeId> = self
480 .nodes_by_name
481 .iter()
482 .filter_map(|(name, &id)| {
483 (self.objects_by_name.contains_key(name)
484 || self.notifications_by_name.contains_key(name)
485 || self.groups_by_name.contains_key(name)
486 || self.compliances_by_name.contains_key(name)
487 || self.capabilities_by_name.contains_key(name))
488 .then_some(id)
489 })
490 .collect();
491
492 self.objects
493 .iter()
494 .map(|&id| Symbol::Object(id))
495 .chain(self.types.iter().map(|&id| Symbol::Type(id)))
496 .chain(
497 self.notifications
498 .iter()
499 .map(|&id| Symbol::Notification(id)),
500 )
501 .chain(self.groups.iter().map(|&id| Symbol::Group(id)))
502 .chain(self.compliances.iter().map(|&id| Symbol::Compliance(id)))
503 .chain(self.capabilities.iter().map(|&id| Symbol::Capability(id)))
504 .chain(
505 self.nodes
506 .iter()
507 .filter(move |id| !covered_node_ids.contains(id))
508 .map(|&id| Symbol::Node(id)),
509 )
510 }
511}
512
513impl std::fmt::Debug for ModuleData {
514 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
515 f.debug_struct("ModuleData")
516 .field("name", &self.name)
517 .field("language", &self.language)
518 .field("is_base", &self.is_base)
519 .finish()
520 }
521}
522
523#[cfg(test)]
524mod tests {
525 use super::*;
526
527 #[test]
528 fn definitions_include_only_plain_nodes() {
529 let mut module = ModuleData::new("TEST-MIB".to_string());
530
531 let object_id = ObjectId::new(0);
532 let object_node = NodeId::new(10);
533 let plain_node = NodeId::new(11);
534
535 module.add_object("ifIndex", object_id);
536 module.add_node("ifIndex", object_node);
537 module.add_node("internet", plain_node);
538
539 let defs: Vec<_> = module.definitions().collect();
540
541 assert_eq!(defs.len(), 2);
542 assert_eq!(defs[0], Symbol::Object(object_id));
543 assert_eq!(defs[1], Symbol::Node(plain_node));
544 }
545
546 #[test]
547 fn definitions_keep_plain_nodes_on_type_name_collision() {
548 let mut module = ModuleData::new("TEST-MIB".to_string());
549
550 let type_id = TypeId::new(0);
551 let plain_node = NodeId::new(11);
552
553 module.add_type("DisplayString", type_id);
554 module.add_node("DisplayString", plain_node);
555
556 let defs: Vec<_> = module.definitions().collect();
557
558 assert_eq!(defs.len(), 2);
559 assert_eq!(defs[0], Symbol::Type(type_id));
560 assert_eq!(defs[1], Symbol::Node(plain_node));
561 }
562}