mib_rs/mib/types.rs
1//! Shared types used across the resolved MIB model.
2//!
3//! Contains arena id newtypes ([`NodeId`], [`ObjectId`], [`TypeId`], etc.),
4//! supporting data structures ([`Range`], [`NamedValue`], [`DefVal`],
5//! [`IndexEntry`]), and SMI clause representations used by compliance and
6//! capability definitions.
7
8use std::fmt;
9
10use crate::mib::Oid;
11use crate::source::SourceRange;
12use crate::types::{Access, BaseType, IndexEncoding};
13
14/// A single imported symbol with its source location.
15///
16/// Part of an [`Import`] group. The `name` is the symbol as written in the
17/// MIB's IMPORTS clause (e.g. `"ifIndex"`, `"DisplayString"`).
18#[derive(Debug, Clone)]
19pub struct ImportSymbol {
20 /// The symbol name as it appears in the IMPORTS clause.
21 pub name: String,
22 /// Source location of this symbol reference.
23 pub range: SourceRange,
24}
25
26/// A group of symbols imported from a single source module.
27///
28/// Each MIB module's IMPORTS section is represented as a list of `Import`
29/// entries, one per source module.
30#[derive(Debug, Clone)]
31pub struct Import {
32 /// Name of the module being imported from.
33 pub module: String,
34 /// Symbols imported from this module.
35 pub symbols: Vec<ImportSymbol>,
36}
37
38/// Resolver strategy used for one imported symbol.
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub enum ImportResolutionMode {
41 /// The selected source module directly defines the complete import group.
42 Direct,
43 /// A well-known source-module alias selected the defining module.
44 Alias,
45 /// The declared source module forwarded the complete import group.
46 Forwarded,
47 /// The symbol was retained while resolving a mixed direct/forwarded group.
48 Partial,
49 /// No source module candidate could resolve the symbol.
50 Unresolved,
51 /// No target was selected and at least one candidate path was cyclic.
52 Cycle,
53}
54
55impl fmt::Display for ImportResolutionMode {
56 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
57 formatter.write_str(match self {
58 Self::Direct => "direct",
59 Self::Alias => "alias",
60 Self::Forwarded => "forwarded",
61 Self::Partial => "partial",
62 Self::Unresolved => "unresolved",
63 Self::Cycle => "cycle",
64 })
65 }
66}
67
68/// Terminal result of one candidate path attempted during import resolution.
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub enum ImportAttemptOutcome {
71 /// The path reached a module defining the symbol.
72 Resolved,
73 /// The path ended at a loaded module that neither defines nor imports the symbol.
74 SymbolNotDefined,
75 /// The next declared source module was unavailable.
76 ModuleNotFound,
77 /// The path revisited a module.
78 Cycle,
79}
80
81/// Import resolver stage that produced a candidate-path attempt.
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83pub enum ImportResolutionStage {
84 /// Aggregate direct-source candidate scoring.
85 Direct,
86 /// Aggregate well-known module-alias candidate scoring.
87 Alias,
88 /// Aggregate import-forwarding traversal.
89 Forwarding,
90 /// Per-symbol partial-resolution traversal.
91 Partial,
92 /// Terminal failure because the declared source module was unavailable.
93 Unresolved,
94}
95
96impl fmt::Display for ImportResolutionStage {
97 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
98 formatter.write_str(match self {
99 Self::Direct => "direct",
100 Self::Alias => "alias",
101 Self::Forwarding => "forwarding",
102 Self::Partial => "partial",
103 Self::Unresolved => "unresolved",
104 })
105 }
106}
107
108impl fmt::Display for ImportAttemptOutcome {
109 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
110 formatter.write_str(match self {
111 Self::Resolved => "resolved",
112 Self::SymbolNotDefined => "symbol-not-defined",
113 Self::ModuleNotFound => "module-not-found",
114 Self::Cycle => "cycle",
115 })
116 }
117}
118
119/// One exact module-version path observed during live import resolution.
120#[derive(Debug, Clone, PartialEq, Eq)]
121pub struct ImportResolutionAttempt {
122 /// Live resolver stage that executed this attempt.
123 pub stage: ImportResolutionStage,
124 /// Loaded module versions visited by the attempt, including a repeated
125 /// final module for a detected cycle.
126 pub path: Vec<ModuleId>,
127 /// Unavailable module named by the last visited module, when applicable.
128 pub missing_module: Option<String>,
129 /// Terminal result.
130 pub outcome: ImportAttemptOutcome,
131 /// Whether this attempt supplied the retained resolution.
132 pub selected: bool,
133}
134
135/// Retained pre-collapse provenance for one IMPORTS symbol.
136#[derive(Debug, Clone, PartialEq, Eq)]
137pub struct ImportResolution {
138 /// Imported symbol.
139 pub symbol: String,
140 /// Source module name written in the importing module.
141 pub declared_module: String,
142 /// Resolver strategy used for the import group.
143 pub mode: ImportResolutionMode,
144 /// Exact defining module version retained after resolution.
145 pub target: Option<ModuleId>,
146 /// Exact selected forwarding path, excluding the importing module itself.
147 pub selected_path: Vec<ModuleId>,
148 /// Candidate paths attempted before the transitive import map was collapsed.
149 pub attempts: Vec<ImportResolutionAttempt>,
150}
151
152/// An endpoint in a resolved SIZE or value range constraint.
153///
154/// Signed and unsigned literals remain distinct so values above [`i64::MAX`]
155/// are represented exactly. `MIN` and `MAX` are retained when no parent or
156/// base-type bound is available to give them a concrete value. Malformed or
157/// unsupported literals retain their source text in [`Raw`](Self::Raw).
158///
159/// The raw representation means this enum is no longer `Copy`; clone endpoints
160/// when an owned value is required.
161#[derive(Debug, Clone, PartialEq, Eq, Hash)]
162pub enum RangeBound {
163 /// A signed integer literal.
164 Signed(i64),
165 /// An unsigned integer literal.
166 Unsigned(u64),
167 /// The `MIN` keyword.
168 Min,
169 /// The `MAX` keyword.
170 Max,
171 /// An unresolved endpoint preserving its source text.
172 Raw(String),
173}
174
175impl RangeBound {
176 /// Return the endpoint as `i64` when it is concrete and representable.
177 pub fn as_i64(&self) -> Option<i64> {
178 match self {
179 Self::Signed(value) => Some(*value),
180 Self::Unsigned(value) => i64::try_from(*value).ok(),
181 Self::Min | Self::Max | Self::Raw(_) => None,
182 }
183 }
184
185 /// Return the endpoint as `u64` when it is concrete and non-negative.
186 pub fn as_u64(&self) -> Option<u64> {
187 match self {
188 Self::Signed(value) => u64::try_from(*value).ok(),
189 Self::Unsigned(value) => Some(*value),
190 Self::Min | Self::Max | Self::Raw(_) => None,
191 }
192 }
193
194 /// Return whether the endpoint is a signed or unsigned number.
195 pub fn is_concrete(&self) -> bool {
196 matches!(self, Self::Signed(_) | Self::Unsigned(_))
197 }
198
199 pub(crate) fn cmp_value(&self, other: &Self) -> Option<std::cmp::Ordering> {
200 use std::cmp::Ordering;
201 match (self, other) {
202 (Self::Raw(_), _) | (_, Self::Raw(_)) => None,
203 (Self::Min, Self::Min) | (Self::Max, Self::Max) => Some(Ordering::Equal),
204 (Self::Min, _) | (_, Self::Max) => Some(Ordering::Less),
205 (Self::Max, _) | (_, Self::Min) => Some(Ordering::Greater),
206 (Self::Signed(left), Self::Signed(right)) => Some(left.cmp(right)),
207 (Self::Unsigned(left), Self::Unsigned(right)) => Some(left.cmp(right)),
208 (Self::Signed(left), Self::Unsigned(right)) => Some(if *left < 0 {
209 Ordering::Less
210 } else {
211 (*left as u64).cmp(right)
212 }),
213 (Self::Unsigned(left), Self::Signed(right)) => Some(if *right < 0 {
214 Ordering::Greater
215 } else {
216 left.cmp(&(*right as u64))
217 }),
218 }
219 }
220}
221
222impl fmt::Display for RangeBound {
223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224 match self {
225 Self::Signed(value) => write!(f, "{value}"),
226 Self::Unsigned(value) => write!(f, "{value}"),
227 Self::Min => f.write_str("MIN"),
228 Self::Max => f.write_str("MAX"),
229 Self::Raw(value) => f.write_str(value),
230 }
231 }
232}
233
234/// A min..max constraint range, used for both SIZE and value constraints.
235///
236/// For single-value constraints (e.g. `SIZE (6)`), `min` equals `max`.
237#[derive(Debug, Clone, PartialEq, Eq)]
238pub struct Range {
239 /// Lower bound (inclusive).
240 pub min: RangeBound,
241 /// Upper bound (inclusive). Equal to `min` for single-value ranges.
242 pub max: RangeBound,
243 /// Source location of this constraint.
244 pub range: Option<SourceRange>,
245}
246
247impl Range {
248 /// Return whether both endpoints are concrete numeric values.
249 pub fn is_resolved(&self) -> bool {
250 self.min.is_concrete() && self.max.is_concrete()
251 }
252
253 pub(crate) fn contains_i64(&self, value: i64) -> bool {
254 let value = RangeBound::Signed(value);
255 self.min
256 .cmp_value(&value)
257 .is_some_and(|ordering| ordering.is_le())
258 && self
259 .max
260 .cmp_value(&value)
261 .is_some_and(|ordering| ordering.is_ge())
262 }
263
264 pub(crate) fn contains_u64(&self, value: u64) -> bool {
265 let value = RangeBound::Unsigned(value);
266 self.min
267 .cmp_value(&value)
268 .is_some_and(|ordering| ordering.is_le())
269 && self
270 .max
271 .cmp_value(&value)
272 .is_some_and(|ordering| ordering.is_ge())
273 }
274}
275
276impl fmt::Display for Range {
277 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278 if self.min == self.max {
279 write!(f, "{}", self.min)
280 } else {
281 write!(f, "{}..{}", self.min, self.max)
282 }
283 }
284}
285
286/// A labeled integer from an enumeration or BITS definition.
287///
288/// Used in OBJECT-TYPE SYNTAX enumerations, BITS definitions, and
289/// refinement clauses in compliance and capability statements.
290#[derive(Debug, Clone)]
291pub struct NamedValue {
292 /// The textual label.
293 pub label: String,
294 /// The integer value associated with this label.
295 pub value: i64,
296 /// Source location of this named value.
297 pub range: SourceRange,
298}
299
300/// Finds a named value by label in a slice.
301pub(crate) fn find_named_value<'a>(
302 values: &'a [NamedValue],
303 label: &str,
304) -> Option<&'a NamedValue> {
305 values.iter().find(|nv| nv.label == label)
306}
307
308/// A module revision entry from a MODULE-IDENTITY REVISION clause.
309#[derive(Debug, Clone)]
310pub struct Revision {
311 /// Revision timestamp string.
312 pub date: String,
313 /// Free-text description of what changed.
314 pub description: String,
315 /// Source location of this revision clause.
316 pub range: SourceRange,
317}
318
319/// An index component from a table row's INDEX clause.
320///
321/// Indexes can be object-backed (referencing a column like `ifIndex`) or
322/// bare-type indexes (using a type name directly). The
323/// [`encoding`](Self::encoding) field indicates how this index component
324/// is encoded on the wire (see [`IndexEncoding`]).
325#[derive(Debug, Clone)]
326pub struct IndexEntry {
327 /// Name of the index object.
328 pub name: String,
329 /// Resolved object id, if found.
330 pub object: Option<ObjectId>,
331 /// Resolved type of the index object, if found.
332 pub type_id: Option<TypeId>,
333 /// True if this index uses the IMPLIED keyword.
334 pub implied: bool,
335 /// Wire encoding inferred from the index object's type.
336 pub encoding: IndexEncoding,
337 /// Source location of this index entry.
338 pub range: SourceRange,
339}
340
341/// Classify the index encoding from the object's resolved base type and size constraints.
342pub(crate) fn classify_index_encoding(
343 base: BaseType,
344 implied: bool,
345 sizes: &[Range],
346) -> IndexEncoding {
347 match base {
348 BaseType::Integer32
349 | BaseType::Unsigned32
350 | BaseType::Gauge32
351 | BaseType::TimeTicks
352 | BaseType::Counter32
353 | BaseType::Counter64 => IndexEncoding::Integer,
354 BaseType::IpAddress => IndexEncoding::IpAddress,
355 BaseType::OctetString | BaseType::Opaque | BaseType::Bits => {
356 if implied {
357 IndexEncoding::Implied
358 } else if is_fixed_size(sizes) {
359 IndexEncoding::FixedString
360 } else {
361 IndexEncoding::LengthPrefixed
362 }
363 }
364 BaseType::ObjectIdentifier => {
365 if implied {
366 IndexEncoding::Implied
367 } else {
368 IndexEncoding::LengthPrefixed
369 }
370 }
371 _ => IndexEncoding::Unknown,
372 }
373}
374
375pub(crate) fn is_fixed_size(sizes: &[Range]) -> bool {
376 sizes.len() == 1
377 && sizes[0].min == sizes[0].max
378 && sizes[0].min.as_u64().is_some_and(|value| value > 0)
379}
380
381/// Discriminant for the kind of value in a [`DefVal`].
382///
383/// Mirrors the [`DefValValue`] variants but as a simple `Copy` enum,
384/// useful for matching or display without borrowing the value.
385#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
386#[repr(u8)]
387pub enum DefValKind {
388 /// No default value specified.
389 Unset = 0,
390 /// Signed integer value.
391 Int = 1,
392 /// Unsigned integer value.
393 Uint = 2,
394 /// Quoted string value.
395 String = 3,
396 /// Raw byte sequence (hex string).
397 Bytes = 4,
398 /// Enumeration label.
399 Enum = 5,
400 /// Set of BITS labels.
401 Bits = 6,
402 /// Object identifier value.
403 Oid = 7,
404}
405
406impl fmt::Display for DefValKind {
407 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
408 f.write_str(match self {
409 DefValKind::Unset => "unset",
410 DefValKind::Int => "int",
411 DefValKind::Uint => "uint",
412 DefValKind::String => "string",
413 DefValKind::Bytes => "bytes",
414 DefValKind::Enum => "enum",
415 DefValKind::Bits => "bits",
416 DefValKind::Oid => "oid",
417 })
418 }
419}
420
421/// A DEFVAL clause value with both the interpreted value and the raw MIB syntax string.
422///
423/// The [`kind`](DefVal::kind) method returns the discriminant, [`value`](DefVal::value)
424/// returns the interpreted value, and [`raw`](DefVal::raw) returns the original
425/// syntax as written in the MIB source.
426///
427/// Constructed via the named constructors ([`DefVal::int`], [`DefVal::string`], etc.).
428#[derive(Debug, Clone)]
429pub struct DefVal {
430 pub(crate) kind: DefValKind,
431 pub(crate) value: DefValValue,
432 pub(crate) raw: String,
433 pub(crate) oid_ref: Option<OidRef>,
434}
435
436/// The interpreted value of a DEFVAL clause.
437///
438/// Each variant corresponds to a [`DefValKind`] discriminant.
439#[derive(Debug, Clone)]
440pub enum DefValValue {
441 /// No value (corresponds to `DefValKind::Unset`).
442 None,
443 /// Signed integer.
444 Int(i64),
445 /// Unsigned integer.
446 Uint(u64),
447 /// Quoted string.
448 String(String),
449 /// Raw byte sequence.
450 Bytes(Vec<u8>),
451 /// Enumeration label.
452 Enum(String),
453 /// Set of BITS labels.
454 Bits(Vec<String>),
455 /// Object identifier.
456 Oid(Oid),
457}
458
459impl DefVal {
460 /// Create a default value indicating no value was specified.
461 pub fn unset() -> Self {
462 DefVal {
463 kind: DefValKind::Unset,
464 value: DefValValue::None,
465 raw: String::new(),
466 oid_ref: None,
467 }
468 }
469
470 /// Create a signed integer default value.
471 pub fn int(v: i64, raw: String) -> Self {
472 DefVal {
473 kind: DefValKind::Int,
474 value: DefValValue::Int(v),
475 raw,
476 oid_ref: None,
477 }
478 }
479
480 /// Create an unsigned integer default value.
481 pub fn uint(v: u64, raw: String) -> Self {
482 DefVal {
483 kind: DefValKind::Uint,
484 value: DefValValue::Uint(v),
485 raw,
486 oid_ref: None,
487 }
488 }
489
490 /// Create a quoted string default value.
491 pub fn string(v: String, raw: String) -> Self {
492 DefVal {
493 kind: DefValKind::String,
494 value: DefValValue::String(v),
495 raw,
496 oid_ref: None,
497 }
498 }
499
500 /// Create a raw byte sequence default value (from a hex string).
501 pub fn bytes(v: Vec<u8>, raw: String) -> Self {
502 DefVal {
503 kind: DefValKind::Bytes,
504 value: DefValValue::Bytes(v),
505 raw,
506 oid_ref: None,
507 }
508 }
509
510 /// Create an enumeration label default value.
511 pub fn enumeration(label: String, raw: String) -> Self {
512 DefVal {
513 kind: DefValKind::Enum,
514 value: DefValValue::Enum(label),
515 raw,
516 oid_ref: None,
517 }
518 }
519
520 /// Create a BITS set default value.
521 pub fn bits(labels: Vec<String>, raw: String) -> Self {
522 DefVal {
523 kind: DefValKind::Bits,
524 value: DefValValue::Bits(labels),
525 raw,
526 oid_ref: None,
527 }
528 }
529
530 /// Create an OID default value.
531 pub fn oid(oid: Oid, raw: String) -> Self {
532 DefVal {
533 kind: DefValKind::Oid,
534 value: DefValValue::Oid(oid),
535 raw,
536 oid_ref: None,
537 }
538 }
539
540 pub(crate) fn oid_with_ref(oid: Oid, raw: String, oid_ref: OidRef) -> Self {
541 DefVal {
542 kind: DefValKind::Oid,
543 value: DefValValue::Oid(oid),
544 raw,
545 oid_ref: Some(oid_ref),
546 }
547 }
548
549 /// Return the [`DefValKind`] discriminant.
550 pub fn kind(&self) -> DefValKind {
551 self.kind
552 }
553
554 /// Return the raw MIB syntax string as written in the source.
555 pub fn raw(&self) -> &str {
556 &self.raw
557 }
558
559 /// Return the interpreted [`DefValValue`].
560 pub fn value(&self) -> &DefValValue {
561 &self.value
562 }
563
564 /// Return the exact symbolic OID reference used by this default value.
565 pub fn oid_ref(&self) -> Option<&OidRef> {
566 self.oid_ref.as_ref()
567 }
568
569 /// Return `true` if no default value was specified.
570 pub fn is_unset(&self) -> bool {
571 self.kind == DefValKind::Unset
572 }
573}
574
575impl fmt::Display for DefVal {
576 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
577 match &self.value {
578 DefValValue::None => Ok(()),
579 DefValValue::Int(v) => write!(f, "{v}"),
580 DefValValue::Uint(v) => write!(f, "{v}"),
581 DefValValue::String(v) => {
582 write!(f, "\"{}\"", v.replace('"', "\\\""))
583 }
584 DefValValue::Bytes(b) => {
585 write!(f, "0x")?;
586 for byte in b {
587 write!(f, "{byte:02X}")?;
588 }
589 Ok(())
590 }
591 DefValValue::Enum(label) => f.write_str(label),
592 DefValValue::Bits(labels) => {
593 if labels.is_empty() {
594 write!(f, "{{ }}")
595 } else {
596 write!(f, "{{ {} }}", labels.join(", "))
597 }
598 }
599 DefValValue::Oid(_) => f.write_str(&self.raw),
600 }
601 }
602}
603
604/// A MODULE clause within a [`ComplianceData`](super::compliance::ComplianceData) definition.
605///
606/// Specifies the mandatory groups and optional object refinements required
607/// for conformance to a particular module.
608#[derive(Debug, Clone)]
609pub struct ComplianceModule {
610 /// Name of the module this clause applies to.
611 pub module_name: String,
612 /// Groups required for conformance.
613 pub mandatory_groups: Vec<String>,
614 /// Optional GROUP refinements.
615 pub groups: Vec<ComplianceGroup>,
616 /// Optional OBJECT refinements.
617 pub objects: Vec<ComplianceObject>,
618 /// Source location of this MODULE clause.
619 pub range: SourceRange,
620}
621
622/// A GROUP clause within a [`ComplianceModule`].
623///
624/// Represents a conditionally required group, with a description of the
625/// conditions under which it is required.
626#[derive(Debug, Clone)]
627pub struct ComplianceGroup {
628 /// Name of the conditionally required group.
629 pub group: String,
630 /// Description of when this group is required.
631 pub description: String,
632 /// Source location of this GROUP clause.
633 pub range: SourceRange,
634}
635
636/// An OBJECT refinement within a [`ComplianceModule`].
637///
638/// May narrow the syntax, write-syntax, or minimum access level for an
639/// object beyond what the base OBJECT-TYPE definition requires.
640#[derive(Debug, Clone)]
641pub struct ComplianceObject {
642 /// Name of the refined object.
643 pub object: String,
644 /// Restricted SYNTAX, if any.
645 pub syntax: Option<SyntaxConstraints>,
646 /// Restricted WRITE-SYNTAX, if any.
647 pub write_syntax: Option<SyntaxConstraints>,
648 /// Minimum required access level, if specified.
649 pub min_access: Option<Access>,
650 /// Description of the refinement.
651 pub description: String,
652 /// Source location of this OBJECT clause.
653 pub range: SourceRange,
654}
655
656/// A SUPPORTS clause within a [`CapabilityData`](super::capability::CapabilityData) definition.
657///
658/// Lists the included groups from a supported module and any object or
659/// notification variations the agent implements.
660#[derive(Debug, Clone)]
661pub struct CapabilitiesModule {
662 /// Name of the supported module.
663 pub module_name: String,
664 /// Groups included from this module.
665 pub includes: Vec<String>,
666 /// Object VARIATION clauses.
667 pub object_variations: Vec<ObjectVariation>,
668 /// Notification VARIATION clauses.
669 pub notification_variations: Vec<NotificationVariation>,
670 /// Source location of this SUPPORTS clause.
671 pub range: SourceRange,
672}
673
674/// An object VARIATION within a [`CapabilitiesModule`].
675///
676/// Describes implementation-specific deviations for a single object,
677/// including restricted syntax, access overrides, and default values.
678#[derive(Debug, Clone)]
679pub struct ObjectVariation {
680 /// Name of the varied object.
681 pub object: String,
682 /// Restricted SYNTAX, if any.
683 pub syntax: Option<SyntaxConstraints>,
684 /// Restricted WRITE-SYNTAX, if any.
685 pub write_syntax: Option<SyntaxConstraints>,
686 /// Overridden access level, if any.
687 pub access: Option<Access>,
688 /// Objects required for row creation, with their exact resolved defining
689 /// module and OID when available.
690 pub creation_requires: Vec<OidRef>,
691 /// Implementation-specific default value, if any.
692 pub def_val: Option<DefVal>,
693 /// Description of this variation.
694 pub description: String,
695 /// Source location of this VARIATION clause.
696 pub range: SourceRange,
697}
698
699/// A notification VARIATION within a [`CapabilitiesModule`].
700///
701/// Describes implementation-specific deviations for a single notification.
702#[derive(Debug, Clone)]
703pub struct NotificationVariation {
704 /// Name of the varied notification.
705 pub notification: String,
706 /// Overridden access level, if any.
707 pub access: Option<Access>,
708 /// Description of this variation.
709 pub description: String,
710 /// Source location of this VARIATION clause.
711 pub range: SourceRange,
712}
713
714/// Inline syntax constraints from a VARIATION SYNTAX/WRITE-SYNTAX clause
715/// or a MODULE-COMPLIANCE OBJECT refinement.
716///
717/// Represents a restricted view of a type with narrowed ranges, enums, or
718/// BITS values.
719#[derive(Debug, Clone)]
720pub struct SyntaxConstraints {
721 /// Resolved type, if any.
722 pub type_id: Option<TypeId>,
723 /// Effective SIZE constraints after intersection with the resolved type.
724 pub sizes: Vec<Range>,
725 /// SIZE constraints declared directly in this syntax clause.
726 pub declared_sizes: Vec<Range>,
727 /// Whether a SIZE constraint was explicitly declared.
728 ///
729 /// When this is true and `sizes` is empty, the declared constraint has an
730 /// empty intersection with the inherited or base-type constraint.
731 pub sizes_constrained: bool,
732 /// Effective value range constraints after intersection with the resolved type.
733 pub ranges: Vec<Range>,
734 /// Value range constraints declared directly in this syntax clause.
735 pub declared_ranges: Vec<Range>,
736 /// Whether a value range constraint was explicitly declared.
737 ///
738 /// When this is true and `ranges` is empty, the declared constraint has an
739 /// empty intersection with the inherited or base-type constraint.
740 pub ranges_constrained: bool,
741 /// Restricted enumeration values.
742 pub enums: Vec<NamedValue>,
743 /// Restricted BITS values.
744 pub bits: Vec<NamedValue>,
745}
746
747/// SMIv1 TRAP-TYPE specific fields.
748///
749/// Present on [`NotificationData`](super::notification::NotificationData)
750/// instances that originate from TRAP-TYPE definitions.
751#[derive(Debug, Clone)]
752pub struct TrapInfo {
753 /// ENTERPRISE OID name from the TRAP-TYPE definition.
754 pub enterprise: String,
755 /// Numeric trap identifier (the specific-trap number).
756 pub trap_number: u32,
757}
758
759/// Identifies the category of an unresolved reference.
760#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
761#[repr(u8)]
762pub enum UnresolvedKind {
763 /// An unresolved IMPORTS symbol.
764 Import = 0,
765 /// An unresolved type reference.
766 Type = 1,
767 /// An unresolved OID component.
768 Oid = 2,
769 /// An unresolved INDEX object.
770 Index = 3,
771 /// An unresolved OBJECTS member of a notification.
772 NotificationObject = 4,
773}
774
775impl fmt::Display for UnresolvedKind {
776 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
777 f.write_str(match self {
778 UnresolvedKind::Import => "import",
779 UnresolvedKind::Type => "type",
780 UnresolvedKind::Oid => "oid",
781 UnresolvedKind::Index => "index",
782 UnresolvedKind::NotificationObject => "notification-object",
783 })
784 }
785}
786
787/// An unresolved symbol reference collected during resolution.
788///
789/// Available via [`Mib::unresolved`](super::mib::Mib::unresolved).
790#[derive(Debug, Clone)]
791pub struct UnresolvedRef {
792 /// What kind of reference failed to resolve.
793 pub kind: UnresolvedKind,
794 /// The symbol name that could not be resolved.
795 pub symbol: String,
796 /// The module where the reference was used.
797 pub module: String,
798 /// Human-readable explanation of why resolution failed.
799 pub reason: String,
800}
801
802/// A symbolic reference to an OID-bearing definition.
803///
804/// Used both for OID value-assignment components (for example `enterprises` in
805/// `{ enterprises 9 }`) and for resolved conformance references that need to
806/// retain exact defining-module provenance.
807#[derive(Debug, Clone)]
808pub struct OidRef {
809 /// The symbolic name referenced in the OID assignment.
810 pub name: String,
811 /// Source location of this reference.
812 pub range: SourceRange,
813 pub(crate) module: Option<ModuleId>,
814 pub(crate) oid: Option<Oid>,
815}
816
817impl OidRef {
818 /// Return the exact resolved defining module/version, when known.
819 pub fn module_id(&self) -> Option<ModuleId> {
820 self.module
821 }
822
823 /// Return the resolved numeric OID of the referenced symbol, when known.
824 pub fn oid(&self) -> Option<&Oid> {
825 self.oid.as_ref()
826 }
827}
828
829// Arena index types for the resolved model.
830macro_rules! define_id {
831 ($(#[$attr:meta])* $name:ident) => {
832 $(#[$attr])*
833 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
834 pub struct $name(pub(crate) u32);
835
836 impl $name {
837 pub(crate) fn new(index: u32) -> Self {
838 Self(index)
839 }
840
841 /// Return the raw arena index as a `u32`.
842 pub fn index(self) -> u32 {
843 self.0
844 }
845 }
846 };
847}
848
849define_id!(
850 /// Index into the OidTree's node arena.
851 NodeId
852);
853define_id!(
854 /// Index into the Mib's object arena.
855 ObjectId
856);
857define_id!(
858 /// Index into the Mib's type arena.
859 TypeId
860);
861define_id!(
862 /// Index into the Mib's module arena.
863 ModuleId
864);
865define_id!(
866 /// Index into the Mib's notification arena.
867 NotificationId
868);
869define_id!(
870 /// Index into the Mib's group arena.
871 GroupId
872);
873define_id!(
874 /// Index into the Mib's compliance arena.
875 ComplianceId
876);
877define_id!(
878 /// Index into the Mib's capability arena.
879 CapabilityId
880);