1use std::fmt;
4use std::ops::Range;
5use std::sync::Arc;
6
7use crate::mib::Oid;
8
9use super::constraint::ConstraintCheck;
10use super::schema::{
11 IndexComponentSchema, IndexSchema, IndexWireType, IntegerConstraint, IntegerIndexKind,
12 LengthConstraint, VariableFraming,
13};
14use super::value::{IndexValue, IndexValueKind, IndexValueRef};
15
16pub const MAX_INSTANCE_OID_ARCS: usize = 128;
18
19#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
21pub enum ConstraintMode {
22 #[default]
24 Enforce,
25 Report,
27}
28
29#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
31pub enum IncompleteConstraintMode {
32 #[default]
34 Reject,
35 Allow,
37}
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub struct DecodeOptions {
42 max_suffix_arcs: usize,
43 max_value_arcs: usize,
44 max_components: usize,
45 constraint_mode: ConstraintMode,
46}
47
48impl DecodeOptions {
49 #[must_use]
51 pub const fn new(max_suffix_arcs: usize) -> Self {
52 Self {
53 max_suffix_arcs,
54 max_value_arcs: max_suffix_arcs,
55 max_components: usize::MAX,
56 constraint_mode: ConstraintMode::Enforce,
57 }
58 }
59
60 #[must_use]
62 pub const fn with_max_value_arcs(mut self, maximum: usize) -> Self {
63 self.max_value_arcs = maximum;
64 self
65 }
66
67 #[must_use]
69 pub const fn with_max_components(mut self, maximum: usize) -> Self {
70 self.max_components = maximum;
71 self
72 }
73
74 #[must_use]
76 pub const fn with_constraint_mode(mut self, mode: ConstraintMode) -> Self {
77 self.constraint_mode = mode;
78 self
79 }
80
81 #[must_use]
83 pub const fn max_suffix_arcs(self) -> usize {
84 self.max_suffix_arcs
85 }
86}
87
88#[derive(Clone, Copy, Debug, PartialEq, Eq)]
90pub struct EncodeOptions {
91 max_suffix_arcs: usize,
92 max_value_arcs: usize,
93 incomplete_constraints: IncompleteConstraintMode,
94}
95
96impl EncodeOptions {
97 #[must_use]
99 pub const fn new(max_suffix_arcs: usize) -> Self {
100 Self {
101 max_suffix_arcs,
102 max_value_arcs: max_suffix_arcs,
103 incomplete_constraints: IncompleteConstraintMode::Reject,
104 }
105 }
106
107 #[must_use]
109 pub const fn with_max_value_arcs(mut self, maximum: usize) -> Self {
110 self.max_value_arcs = maximum;
111 self
112 }
113
114 #[must_use]
116 pub const fn with_incomplete_constraints(mut self, mode: IncompleteConstraintMode) -> Self {
117 self.incomplete_constraints = mode;
118 self
119 }
120
121 #[must_use]
123 pub const fn max_suffix_arcs(self) -> usize {
124 self.max_suffix_arcs
125 }
126}
127
128#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
130pub enum IndexConstraintViolation {
131 #[error("integer value {value} is outside the effective range")]
133 IntegerRange {
134 value: i64,
136 },
137 #[error("integer value {value} is not in the effective enumeration")]
139 IntegerEnumeration {
140 value: i64,
142 },
143 #[error("value length {length} is outside the effective SIZE constraint")]
148 Length {
149 length: usize,
151 },
152}
153
154#[derive(Clone, Debug, PartialEq, Eq)]
156pub struct ReportedIndexViolation {
157 component_position: usize,
158 violation: IndexConstraintViolation,
159}
160
161impl ReportedIndexViolation {
162 #[must_use]
164 pub const fn component_position(&self) -> usize {
165 self.component_position
166 }
167
168 #[must_use]
170 pub const fn violation(&self) -> &IndexConstraintViolation {
171 &self.violation
172 }
173}
174
175#[derive(Clone, Debug, PartialEq, Eq)]
177pub struct DecodedRowIndex<'schema, 'suffix> {
178 schema: &'schema IndexSchema,
179 suffix: &'suffix [u32],
180 values: Box<[IndexValue]>,
181 ranges: Box<[Range<usize>]>,
182 violations: Box<[ReportedIndexViolation]>,
183}
184
185impl<'schema, 'suffix> DecodedRowIndex<'schema, 'suffix> {
186 #[must_use]
188 pub const fn schema(&self) -> &'schema IndexSchema {
189 self.schema
190 }
191
192 #[must_use]
194 pub const fn raw_arcs(&self) -> &'suffix [u32] {
195 self.suffix
196 }
197
198 #[must_use]
200 pub const fn values(&self) -> &[IndexValue] {
201 &self.values
202 }
203
204 #[must_use]
206 pub fn components(&self) -> DecodedIndexComponents<'_, 'schema, 'suffix> {
207 DecodedIndexComponents {
208 decoded: self,
209 position: 0,
210 }
211 }
212
213 #[must_use]
215 pub const fn violations(&self) -> &[ReportedIndexViolation] {
216 &self.violations
217 }
218}
219
220#[derive(Clone, Copy, Debug)]
222pub struct DecodedIndexComponent<'a, 'schema, 'suffix> {
223 schema: &'schema IndexComponentSchema,
224 value: &'a IndexValue,
225 arc_range: &'a Range<usize>,
226 raw_arcs: &'suffix [u32],
227}
228
229impl<'a, 'schema, 'suffix> DecodedIndexComponent<'a, 'schema, 'suffix> {
230 #[must_use]
232 pub const fn schema(&self) -> &'schema IndexComponentSchema {
233 self.schema
234 }
235
236 #[must_use]
238 pub fn name(&self) -> &'schema str {
239 self.schema.name()
240 }
241
242 #[must_use]
244 pub const fn value(&self) -> &'a IndexValue {
245 self.value
246 }
247
248 #[must_use]
252 pub fn arc_range(&self) -> Range<usize> {
253 self.arc_range.clone()
254 }
255
256 #[must_use]
258 pub const fn raw_arcs(&self) -> &'suffix [u32] {
259 self.raw_arcs
260 }
261}
262
263pub struct DecodedIndexComponents<'a, 'schema, 'suffix> {
265 decoded: &'a DecodedRowIndex<'schema, 'suffix>,
266 position: usize,
267}
268
269impl<'a, 'schema, 'suffix> Iterator for DecodedIndexComponents<'a, 'schema, 'suffix> {
270 type Item = DecodedIndexComponent<'a, 'schema, 'suffix>;
271
272 fn next(&mut self) -> Option<Self::Item> {
273 let position = self.position;
274 let schema = self.decoded.schema.components().get(position)?;
275 let value = &self.decoded.values[position];
276 let arc_range = &self.decoded.ranges[position];
277 self.position += 1;
278 Some(DecodedIndexComponent {
279 schema,
280 value,
281 arc_range,
282 raw_arcs: &self.decoded.suffix[arc_range.clone()],
283 })
284 }
285
286 fn size_hint(&self) -> (usize, Option<usize>) {
287 let remaining = self.decoded.values.len() - self.position;
288 (remaining, Some(remaining))
289 }
290}
291
292impl ExactSizeIterator for DecodedIndexComponents<'_, '_, '_> {}
293
294#[derive(Clone, Debug, PartialEq, Eq)]
296pub struct DecodedPrefixComponent<'suffix> {
297 position: usize,
298 value: IndexValue,
299 arc_range: Range<usize>,
300 raw_arcs: &'suffix [u32],
301}
302
303impl<'suffix> DecodedPrefixComponent<'suffix> {
304 #[must_use]
306 pub const fn position(&self) -> usize {
307 self.position
308 }
309
310 #[must_use]
312 pub const fn value(&self) -> &IndexValue {
313 &self.value
314 }
315
316 #[must_use]
320 pub fn arc_range(&self) -> Range<usize> {
321 self.arc_range.clone()
322 }
323
324 #[must_use]
326 pub const fn raw_arcs(&self) -> &'suffix [u32] {
327 self.raw_arcs
328 }
329}
330
331#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
333pub enum IndexDecodeErrorKind {
334 #[error("suffix has {actual} arcs, exceeding the operation limit of {maximum}")]
336 SuffixTooLong {
337 actual: usize,
339 maximum: usize,
341 },
342 #[error("schema has {actual} components, exceeding the operation limit of {maximum}")]
344 TooManyComponents {
345 actual: usize,
347 maximum: usize,
349 },
350 #[error("component needs {needed} arcs but only {available} remain")]
354 Truncated {
355 needed: usize,
357 available: usize,
359 },
360 #[error("declared length {declared} exceeds the value limit of {maximum}")]
362 LengthPrefixTooLarge {
363 declared: u32,
365 maximum: usize,
367 },
368 #[error("value has {actual} arcs, exceeding the value limit of {maximum}")]
370 ValueTooLong {
371 actual: usize,
373 maximum: usize,
375 },
376 #[error("arc value {value} is not an octet")]
378 InvalidOctet {
379 value: u32,
381 },
382 #[error("arc value {value} is outside the non-negative Integer32 index domain")]
384 Integer32OutOfDomain {
385 value: u32,
387 },
388 #[error("{count} trailing arcs remain")]
390 TrailingArcs {
391 count: usize,
393 },
394 #[error("{0}")]
396 ConstraintViolation(IndexConstraintViolation),
397}
398
399#[derive(Clone, Debug, PartialEq, Eq)]
401pub struct IndexDecodeError<'suffix> {
402 kind: IndexDecodeErrorKind,
403 component_position: Option<usize>,
404 component_name: Option<String>,
405 arc_offset: usize,
406 decoded_prefix: Box<[DecodedPrefixComponent<'suffix>]>,
407 remaining: &'suffix [u32],
408}
409
410impl<'suffix> IndexDecodeError<'suffix> {
411 #[must_use]
413 pub const fn kind(&self) -> &IndexDecodeErrorKind {
414 &self.kind
415 }
416
417 #[must_use]
422 pub const fn component_position(&self) -> Option<usize> {
423 self.component_position
424 }
425
426 #[must_use]
431 pub fn component_name(&self) -> Option<&str> {
432 self.component_name.as_deref()
433 }
434
435 #[must_use]
440 pub const fn arc_offset(&self) -> usize {
441 self.arc_offset
442 }
443
444 #[must_use]
446 pub const fn decoded_prefix(&self) -> &[DecodedPrefixComponent<'suffix>] {
447 &self.decoded_prefix
448 }
449
450 #[must_use]
456 pub const fn remaining_arcs(&self) -> &'suffix [u32] {
457 self.remaining
458 }
459}
460
461impl fmt::Display for IndexDecodeError<'_> {
462 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
463 if let (Some(position), Some(name)) = (self.component_position, &self.component_name) {
464 write!(
465 f,
466 "failed to decode index component {position} ({name}) at suffix arc {}: {}",
467 self.arc_offset, self.kind
468 )
469 } else {
470 write!(
471 f,
472 "failed to decode index suffix at arc {}: {}",
473 self.arc_offset, self.kind
474 )
475 }
476 }
477}
478
479impl std::error::Error for IndexDecodeError<'_> {}
480
481#[derive(Clone, Debug, PartialEq, Eq, Hash)]
483pub struct IndexSuffix(Box<[u32]>);
484
485impl IndexSuffix {
486 #[must_use]
488 pub const fn len(&self) -> usize {
489 self.0.len()
490 }
491
492 #[must_use]
494 pub const fn is_empty(&self) -> bool {
495 self.0.is_empty()
496 }
497}
498
499impl AsRef<[u32]> for IndexSuffix {
500 fn as_ref(&self) -> &[u32] {
501 &self.0
502 }
503}
504
505impl std::ops::Deref for IndexSuffix {
506 type Target = [u32];
507
508 fn deref(&self) -> &Self::Target {
509 &self.0
510 }
511}
512
513impl From<IndexSuffix> for Oid {
514 fn from(value: IndexSuffix) -> Self {
515 Oid::from(value.0.into_vec())
516 }
517}
518
519impl From<&IndexSuffix> for Oid {
520 fn from(value: &IndexSuffix) -> Self {
521 Oid::from(value.as_ref())
522 }
523}
524
525#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
527pub enum IndexEncodeErrorKind {
528 #[error("too few values: expected {expected}, received {actual}")]
530 TooFewValues {
531 expected: usize,
533 actual: usize,
535 },
536 #[error("too many values: expected {expected}")]
538 TooManyValues {
539 expected: usize,
541 },
542 #[error("wrong value kind: expected {expected}, received {actual}")]
544 WrongValueKind {
545 expected: IndexValueKind,
547 actual: IndexValueKind,
549 },
550 #[error("negative Integer32 value {value} cannot be encoded as an OID arc")]
552 NegativeInteger32 {
553 value: i32,
555 },
556 #[error("fixed component needs {expected} value arcs, received {actual}")]
558 FixedLength {
559 expected: usize,
561 actual: usize,
563 },
564 #[error("value has {actual} arcs, exceeding the value limit of {maximum}")]
566 ValueTooLong {
567 actual: usize,
569 maximum: usize,
571 },
572 #[error("value length {length} cannot be represented by one OID arc")]
574 LengthPrefixOverflow {
575 length: usize,
577 },
578 #[error("encoded suffix would have {actual} arcs, exceeding the limit of {maximum}")]
580 SuffixTooLong {
581 actual: usize,
583 maximum: usize,
585 },
586 #[error("{0}")]
588 ConstraintViolation(IndexConstraintViolation),
589 #[error("constraint validity is indeterminate because metadata is unresolved")]
591 IndeterminateConstraint,
592 #[error("arithmetic overflow while encoding the suffix")]
594 ArithmeticOverflow,
595}
596
597#[derive(Clone, Debug, PartialEq, Eq)]
599pub struct IndexEncodeError {
600 kind: IndexEncodeErrorKind,
601 component_position: Option<usize>,
602 component_name: Option<String>,
603}
604
605impl IndexEncodeError {
606 #[must_use]
608 pub const fn kind(&self) -> &IndexEncodeErrorKind {
609 &self.kind
610 }
611
612 #[must_use]
617 pub const fn component_position(&self) -> Option<usize> {
618 self.component_position
619 }
620
621 #[must_use]
626 pub fn component_name(&self) -> Option<&str> {
627 self.component_name.as_deref()
628 }
629}
630
631impl fmt::Display for IndexEncodeError {
632 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
633 if let (Some(position), Some(name)) = (self.component_position, &self.component_name) {
634 write!(
635 f,
636 "failed to encode index component {position} ({name}): {}",
637 self.kind
638 )
639 } else {
640 write!(f, "failed to encode index suffix: {}", self.kind)
641 }
642 }
643}
644
645impl std::error::Error for IndexEncodeError {}
646
647impl IndexSchema {
648 pub fn decode_exact<'schema, 'suffix>(
653 &'schema self,
654 suffix: &'suffix [u32],
655 options: DecodeOptions,
656 ) -> Result<DecodedRowIndex<'schema, 'suffix>, IndexDecodeError<'suffix>> {
657 if suffix.len() > options.max_suffix_arcs {
658 return Err(IndexDecodeError {
659 kind: IndexDecodeErrorKind::SuffixTooLong {
660 actual: suffix.len(),
661 maximum: options.max_suffix_arcs,
662 },
663 component_position: None,
664 component_name: None,
665 arc_offset: 0,
666 decoded_prefix: Box::new([]),
667 remaining: suffix,
668 });
669 }
670 if self.len() > options.max_components {
671 return Err(IndexDecodeError {
672 kind: IndexDecodeErrorKind::TooManyComponents {
673 actual: self.len(),
674 maximum: options.max_components,
675 },
676 component_position: None,
677 component_name: None,
678 arc_offset: 0,
679 decoded_prefix: Box::new([]),
680 remaining: suffix,
681 });
682 }
683
684 let mut values = Vec::with_capacity(self.len());
685 let mut ranges = Vec::with_capacity(self.len());
686 let mut violations = Vec::new();
687 let mut position = 0usize;
688
689 for (component_position, component) in self.components().iter().enumerate() {
690 let start = position;
691 let value = match component.wire_type() {
692 IndexWireType::Integer { kind, allowed } => {
693 let Some(&arc) = suffix.get(position) else {
694 return Err(decode_error(
695 IndexDecodeErrorKind::Truncated {
696 needed: 1,
697 available: 0,
698 },
699 component_position,
700 component,
701 start,
702 &values,
703 &ranges,
704 suffix,
705 ));
706 };
707 position += 1;
708 let value = decode_integer(*kind, arc).map_err(|kind| {
709 decode_error(
710 kind,
711 component_position,
712 component,
713 start,
714 &values,
715 &ranges,
716 suffix,
717 )
718 })?;
719 if let Some(violation) = integer_violation(allowed, i64::from(arc)) {
720 handle_decode_violation(
721 options.constraint_mode,
722 component_position,
723 component,
724 start,
725 violation,
726 &mut violations,
727 &values,
728 &ranges,
729 suffix,
730 )?;
731 }
732 value
733 }
734 IndexWireType::IpAddress => {
735 let data = take_value_arcs(
736 suffix,
737 position,
738 4,
739 options.max_value_arcs,
740 component_position,
741 component,
742 &values,
743 &ranges,
744 )?;
745 if let Some((offset, value)) = invalid_octet(data) {
746 return Err(decode_error_at(
747 IndexDecodeErrorKind::InvalidOctet { value },
748 component_position,
749 component,
750 start + offset,
751 start,
752 &values,
753 &ranges,
754 suffix,
755 ));
756 }
757 position += 4;
758 IndexValue::IpAddress(std::array::from_fn(|offset| data[offset] as u8))
759 }
760 IndexWireType::Octets {
761 kind,
762 framing,
763 lengths,
764 } => {
765 let (data_start, length) = framed_value(
766 *framing,
767 suffix,
768 position,
769 options.max_value_arcs,
770 component_position,
771 component,
772 &values,
773 &ranges,
774 )?;
775 let data = &suffix[data_start..data_start + length];
776 if let Some((offset, value)) = invalid_octet(data) {
777 return Err(decode_error_at(
778 IndexDecodeErrorKind::InvalidOctet { value },
779 component_position,
780 component,
781 data_start + offset,
782 start,
783 &values,
784 &ranges,
785 suffix,
786 ));
787 }
788 if let Some(violation) = length_violation(lengths, length) {
789 handle_decode_violation(
790 options.constraint_mode,
791 component_position,
792 component,
793 start,
794 violation,
795 &mut violations,
796 &values,
797 &ranges,
798 suffix,
799 )?;
800 }
801 position = data_start + length;
802 let bytes: Vec<u8> = data.iter().map(|arc| *arc as u8).collect();
803 match kind {
804 super::schema::OctetIndexKind::OctetString => {
805 IndexValue::OctetString(bytes)
806 }
807 super::schema::OctetIndexKind::Bits => IndexValue::Bits(bytes),
808 super::schema::OctetIndexKind::Opaque => IndexValue::Opaque(bytes),
809 }
810 }
811 IndexWireType::ObjectIdentifier { framing, lengths } => {
812 let (data_start, length) = framed_value(
813 *framing,
814 suffix,
815 position,
816 options.max_value_arcs,
817 component_position,
818 component,
819 &values,
820 &ranges,
821 )?;
822 if let Some(violation) = length_violation(lengths, length) {
823 handle_decode_violation(
824 options.constraint_mode,
825 component_position,
826 component,
827 start,
828 violation,
829 &mut violations,
830 &values,
831 &ranges,
832 suffix,
833 )?;
834 }
835 position = data_start + length;
836 IndexValue::ObjectIdentifier(Oid::from(&suffix[data_start..position]))
837 }
838 };
839 values.push(value);
840 ranges.push(start..position);
841 }
842
843 if position != suffix.len() {
844 return Err(decode_whole_error(
845 IndexDecodeErrorKind::TrailingArcs {
846 count: suffix.len() - position,
847 },
848 position,
849 &values,
850 &ranges,
851 suffix,
852 ));
853 }
854
855 Ok(DecodedRowIndex {
856 schema: self,
857 suffix,
858 values: values.into_boxed_slice(),
859 ranges: ranges.into_boxed_slice(),
860 violations: violations.into_boxed_slice(),
861 })
862 }
863
864 pub fn encode_canonical<'a>(
868 &self,
869 values: impl IntoIterator<Item = IndexValueRef<'a>>,
870 options: EncodeOptions,
871 ) -> Result<IndexSuffix, IndexEncodeError> {
872 let mut values = values.into_iter();
873 let mut suffix =
874 Vec::with_capacity(self.minimum_suffix_arcs().min(options.max_suffix_arcs));
875
876 for (position, component) in self.components().iter().enumerate() {
877 let Some(value) = values.next() else {
878 return Err(encode_whole_error(IndexEncodeErrorKind::TooFewValues {
879 expected: self.len(),
880 actual: position,
881 }));
882 };
883 if value.kind() != component.value_kind() {
884 return Err(encode_error(
885 IndexEncodeErrorKind::WrongValueKind {
886 expected: component.value_kind(),
887 actual: value.kind(),
888 },
889 position,
890 component,
891 ));
892 }
893
894 match (component.wire_type(), value) {
895 (IndexWireType::Integer { allowed, .. }, value) => {
896 let integer = integer_ref(value)
897 .map_err(|kind| encode_error(kind, position, component))?;
898 validate_integer_encode(
899 allowed,
900 integer,
901 options.incomplete_constraints,
902 position,
903 component,
904 )?;
905 push_component(&suffix, 1, options.max_suffix_arcs, position, component)?;
906 suffix.push(integer as u32);
907 }
908 (IndexWireType::IpAddress, IndexValueRef::IpAddress(address)) => {
909 push_component(&suffix, 4, options.max_suffix_arcs, position, component)?;
910 suffix.extend(address.map(u32::from));
911 }
912 (
913 IndexWireType::Octets {
914 framing, lengths, ..
915 },
916 IndexValueRef::OctetString(bytes)
917 | IndexValueRef::Bits(bytes)
918 | IndexValueRef::Opaque(bytes),
919 ) => encode_variable(
920 &mut suffix,
921 bytes.iter().copied().map(u32::from),
922 bytes.len(),
923 *framing,
924 lengths,
925 options,
926 position,
927 component,
928 )?,
929 (
930 IndexWireType::ObjectIdentifier { framing, lengths },
931 IndexValueRef::ObjectIdentifier(arcs),
932 ) => encode_variable(
933 &mut suffix,
934 arcs.iter().copied(),
935 arcs.len(),
936 *framing,
937 lengths,
938 options,
939 position,
940 component,
941 )?,
942 _ => unreachable!("value kind checked before encoding"),
943 }
944 }
945
946 if values.next().is_some() {
947 return Err(encode_whole_error(IndexEncodeErrorKind::TooManyValues {
948 expected: self.len(),
949 }));
950 }
951 Ok(IndexSuffix(suffix.into_boxed_slice()))
952 }
953}
954
955#[derive(Clone, Debug)]
957pub struct BoundIndexCodec {
958 schema: Arc<IndexSchema>,
959 max_suffix_arcs: usize,
960}
961
962impl BoundIndexCodec {
963 pub fn new(schema: Arc<IndexSchema>, max_suffix_arcs: usize) -> Result<Self, IndexBindError> {
965 if schema.minimum_suffix_arcs() > max_suffix_arcs {
966 return Err(IndexBindError::MinimumSuffixTooLong {
967 minimum: schema.minimum_suffix_arcs(),
968 maximum: max_suffix_arcs,
969 });
970 }
971 Ok(Self {
972 schema,
973 max_suffix_arcs,
974 })
975 }
976
977 pub fn for_object_oid(
979 schema: Arc<IndexSchema>,
980 object_oid: &Oid,
981 ) -> Result<Self, IndexBindError> {
982 let Some(maximum) = MAX_INSTANCE_OID_ARCS.checked_sub(object_oid.len()) else {
983 return Err(IndexBindError::ObjectOidTooLong {
984 actual: object_oid.len(),
985 maximum: MAX_INSTANCE_OID_ARCS,
986 });
987 };
988 Self::new(schema, maximum)
989 }
990
991 #[must_use]
993 pub fn schema(&self) -> &Arc<IndexSchema> {
994 &self.schema
995 }
996
997 #[must_use]
999 pub const fn max_suffix_arcs(&self) -> usize {
1000 self.max_suffix_arcs
1001 }
1002
1003 pub fn decode_exact<'schema, 'suffix>(
1005 &'schema self,
1006 suffix: &'suffix [u32],
1007 mode: ConstraintMode,
1008 ) -> Result<DecodedRowIndex<'schema, 'suffix>, IndexDecodeError<'suffix>> {
1009 self.schema.decode_exact(
1010 suffix,
1011 DecodeOptions::new(self.max_suffix_arcs).with_constraint_mode(mode),
1012 )
1013 }
1014
1015 pub fn encode_canonical<'a>(
1018 &self,
1019 values: impl IntoIterator<Item = IndexValueRef<'a>>,
1020 ) -> Result<IndexSuffix, IndexEncodeError> {
1021 self.encode_canonical_with_incomplete_constraints(values, IncompleteConstraintMode::Reject)
1022 }
1023
1024 pub fn encode_canonical_with_incomplete_constraints<'a>(
1027 &self,
1028 values: impl IntoIterator<Item = IndexValueRef<'a>>,
1029 mode: IncompleteConstraintMode,
1030 ) -> Result<IndexSuffix, IndexEncodeError> {
1031 self.schema.encode_canonical(
1032 values,
1033 EncodeOptions::new(self.max_suffix_arcs).with_incomplete_constraints(mode),
1034 )
1035 }
1036}
1037
1038#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
1040pub enum IndexBindError {
1041 #[error("object OID has {actual} arcs, exceeding the complete limit of {maximum}")]
1043 ObjectOidTooLong {
1044 actual: usize,
1046 maximum: usize,
1048 },
1049 #[error("schema needs at least {minimum} suffix arcs, exceeding the limit of {maximum}")]
1051 MinimumSuffixTooLong {
1052 minimum: usize,
1054 maximum: usize,
1056 },
1057}
1058
1059fn decode_integer(kind: IntegerIndexKind, arc: u32) -> Result<IndexValue, IndexDecodeErrorKind> {
1060 Ok(match kind {
1061 IntegerIndexKind::Integer32 => IndexValue::Integer32(
1062 i32::try_from(arc)
1063 .map_err(|_| IndexDecodeErrorKind::Integer32OutOfDomain { value: arc })?,
1064 ),
1065 IntegerIndexKind::Unsigned32 => IndexValue::Unsigned32(arc),
1066 IntegerIndexKind::Gauge32 => IndexValue::Gauge32(arc),
1067 IntegerIndexKind::TimeTicks => IndexValue::TimeTicks(arc),
1068 IntegerIndexKind::Counter32 => IndexValue::Counter32(arc),
1069 })
1070}
1071
1072fn integer_violation(allowed: &IntegerConstraint, value: i64) -> Option<IndexConstraintViolation> {
1073 if allowed.ranges().check(&value) == ConstraintCheck::Violation {
1074 Some(IndexConstraintViolation::IntegerRange { value })
1075 } else if allowed
1076 .enumeration()
1077 .is_some_and(|enumeration| enumeration.binary_search(&value).is_err())
1078 {
1079 Some(IndexConstraintViolation::IntegerEnumeration { value })
1080 } else {
1081 None
1082 }
1083}
1084
1085fn length_violation(allowed: &LengthConstraint, length: usize) -> Option<IndexConstraintViolation> {
1086 (allowed.check(&length) == ConstraintCheck::Violation)
1087 .then_some(IndexConstraintViolation::Length { length })
1088}
1089
1090#[allow(clippy::too_many_arguments)]
1091fn handle_decode_violation<'suffix>(
1092 mode: ConstraintMode,
1093 position: usize,
1094 component: &IndexComponentSchema,
1095 start: usize,
1096 violation: IndexConstraintViolation,
1097 violations: &mut Vec<ReportedIndexViolation>,
1098 values: &[IndexValue],
1099 ranges: &[Range<usize>],
1100 suffix: &'suffix [u32],
1101) -> Result<(), IndexDecodeError<'suffix>> {
1102 match mode {
1103 ConstraintMode::Enforce => Err(decode_error(
1104 IndexDecodeErrorKind::ConstraintViolation(violation),
1105 position,
1106 component,
1107 start,
1108 values,
1109 ranges,
1110 suffix,
1111 )),
1112 ConstraintMode::Report => {
1113 violations.push(ReportedIndexViolation {
1114 component_position: position,
1115 violation,
1116 });
1117 Ok(())
1118 }
1119 }
1120}
1121
1122#[allow(clippy::too_many_arguments)]
1123fn take_value_arcs<'suffix>(
1124 suffix: &'suffix [u32],
1125 start: usize,
1126 length: usize,
1127 maximum: usize,
1128 position: usize,
1129 component: &IndexComponentSchema,
1130 values: &[IndexValue],
1131 ranges: &[Range<usize>],
1132) -> Result<&'suffix [u32], IndexDecodeError<'suffix>> {
1133 if length > maximum {
1134 return Err(decode_error(
1135 IndexDecodeErrorKind::ValueTooLong {
1136 actual: length,
1137 maximum,
1138 },
1139 position,
1140 component,
1141 start,
1142 values,
1143 ranges,
1144 suffix,
1145 ));
1146 }
1147 let available = suffix.len().saturating_sub(start);
1148 if available < length {
1149 return Err(decode_error(
1150 IndexDecodeErrorKind::Truncated {
1151 needed: length,
1152 available,
1153 },
1154 position,
1155 component,
1156 start,
1157 values,
1158 ranges,
1159 suffix,
1160 ));
1161 }
1162 Ok(&suffix[start..start + length])
1163}
1164
1165#[allow(clippy::too_many_arguments)]
1166fn framed_value<'suffix>(
1167 framing: VariableFraming,
1168 suffix: &'suffix [u32],
1169 start: usize,
1170 maximum: usize,
1171 position: usize,
1172 component: &IndexComponentSchema,
1173 values: &[IndexValue],
1174 ranges: &[Range<usize>],
1175) -> Result<(usize, usize), IndexDecodeError<'suffix>> {
1176 match framing {
1177 VariableFraming::Fixed(length) => {
1178 take_value_arcs(
1179 suffix, start, length, maximum, position, component, values, ranges,
1180 )?;
1181 Ok((start, length))
1182 }
1183 VariableFraming::LengthPrefixed => {
1184 let Some(&declared) = suffix.get(start) else {
1185 return Err(decode_error(
1186 IndexDecodeErrorKind::Truncated {
1187 needed: 1,
1188 available: 0,
1189 },
1190 position,
1191 component,
1192 start,
1193 values,
1194 ranges,
1195 suffix,
1196 ));
1197 };
1198 let Ok(length) = usize::try_from(declared) else {
1199 return Err(decode_error(
1200 IndexDecodeErrorKind::LengthPrefixTooLarge { declared, maximum },
1201 position,
1202 component,
1203 start,
1204 values,
1205 ranges,
1206 suffix,
1207 ));
1208 };
1209 if length > maximum {
1210 return Err(decode_error(
1211 IndexDecodeErrorKind::LengthPrefixTooLarge { declared, maximum },
1212 position,
1213 component,
1214 start,
1215 values,
1216 ranges,
1217 suffix,
1218 ));
1219 }
1220 let data_start = start + 1;
1221 let available = suffix.len().saturating_sub(data_start);
1222 if available < length {
1223 return Err(decode_error(
1224 IndexDecodeErrorKind::Truncated {
1225 needed: length + 1,
1226 available: available + 1,
1227 },
1228 position,
1229 component,
1230 start,
1231 values,
1232 ranges,
1233 suffix,
1234 ));
1235 }
1236 Ok((data_start, length))
1237 }
1238 VariableFraming::Implied => {
1239 let length = suffix.len().saturating_sub(start);
1240 if length > maximum {
1241 return Err(decode_error(
1242 IndexDecodeErrorKind::ValueTooLong {
1243 actual: length,
1244 maximum,
1245 },
1246 position,
1247 component,
1248 start,
1249 values,
1250 ranges,
1251 suffix,
1252 ));
1253 }
1254 Ok((start, length))
1255 }
1256 }
1257}
1258
1259fn invalid_octet(arcs: &[u32]) -> Option<(usize, u32)> {
1260 arcs.iter()
1261 .copied()
1262 .enumerate()
1263 .find(|(_, arc)| *arc > u32::from(u8::MAX))
1264}
1265
1266fn decode_error<'suffix>(
1267 kind: IndexDecodeErrorKind,
1268 position: usize,
1269 component: &IndexComponentSchema,
1270 start: usize,
1271 values: &[IndexValue],
1272 ranges: &[Range<usize>],
1273 suffix: &'suffix [u32],
1274) -> IndexDecodeError<'suffix> {
1275 decode_error_at(
1276 kind, position, component, start, start, values, ranges, suffix,
1277 )
1278}
1279
1280#[allow(clippy::too_many_arguments)]
1281fn decode_error_at<'suffix>(
1282 kind: IndexDecodeErrorKind,
1283 position: usize,
1284 component: &IndexComponentSchema,
1285 offset: usize,
1286 remaining_start: usize,
1287 values: &[IndexValue],
1288 ranges: &[Range<usize>],
1289 suffix: &'suffix [u32],
1290) -> IndexDecodeError<'suffix> {
1291 IndexDecodeError {
1292 kind,
1293 component_position: Some(position),
1294 component_name: Some(component.name().to_string()),
1295 arc_offset: offset,
1296 decoded_prefix: make_decoded_prefix(values, ranges, suffix),
1297 remaining: &suffix[remaining_start..],
1298 }
1299}
1300
1301fn decode_whole_error<'suffix>(
1302 kind: IndexDecodeErrorKind,
1303 offset: usize,
1304 values: &[IndexValue],
1305 ranges: &[Range<usize>],
1306 suffix: &'suffix [u32],
1307) -> IndexDecodeError<'suffix> {
1308 IndexDecodeError {
1309 kind,
1310 component_position: None,
1311 component_name: None,
1312 arc_offset: offset,
1313 decoded_prefix: make_decoded_prefix(values, ranges, suffix),
1314 remaining: &suffix[offset..],
1315 }
1316}
1317
1318fn make_decoded_prefix<'suffix>(
1319 values: &[IndexValue],
1320 ranges: &[Range<usize>],
1321 suffix: &'suffix [u32],
1322) -> Box<[DecodedPrefixComponent<'suffix>]> {
1323 values
1324 .iter()
1325 .cloned()
1326 .zip(ranges.iter().cloned())
1327 .enumerate()
1328 .map(|(position, (value, arc_range))| DecodedPrefixComponent {
1329 position,
1330 value,
1331 raw_arcs: &suffix[arc_range.clone()],
1332 arc_range,
1333 })
1334 .collect()
1335}
1336
1337fn integer_ref(value: IndexValueRef<'_>) -> Result<i64, IndexEncodeErrorKind> {
1338 match value {
1339 IndexValueRef::Integer32(value) if value < 0 => {
1340 Err(IndexEncodeErrorKind::NegativeInteger32 { value })
1341 }
1342 IndexValueRef::Integer32(value) => Ok(i64::from(value)),
1343 IndexValueRef::Unsigned32(value)
1344 | IndexValueRef::Gauge32(value)
1345 | IndexValueRef::TimeTicks(value)
1346 | IndexValueRef::Counter32(value) => Ok(i64::from(value)),
1347 _ => unreachable!("value kind checked before integer conversion"),
1348 }
1349}
1350
1351fn validate_integer_encode(
1352 allowed: &IntegerConstraint,
1353 value: i64,
1354 incomplete: IncompleteConstraintMode,
1355 position: usize,
1356 component: &IndexComponentSchema,
1357) -> Result<(), IndexEncodeError> {
1358 if let Some(violation) = integer_violation(allowed, value) {
1359 return Err(encode_error(
1360 IndexEncodeErrorKind::ConstraintViolation(violation),
1361 position,
1362 component,
1363 ));
1364 }
1365 if allowed.check(value) == ConstraintCheck::Indeterminate
1366 && incomplete == IncompleteConstraintMode::Reject
1367 {
1368 return Err(encode_error(
1369 IndexEncodeErrorKind::IndeterminateConstraint,
1370 position,
1371 component,
1372 ));
1373 }
1374 Ok(())
1375}
1376
1377#[allow(clippy::too_many_arguments)]
1378fn encode_variable(
1379 suffix: &mut Vec<u32>,
1380 arcs: impl IntoIterator<Item = u32>,
1381 length: usize,
1382 framing: VariableFraming,
1383 lengths: &LengthConstraint,
1384 options: EncodeOptions,
1385 position: usize,
1386 component: &IndexComponentSchema,
1387) -> Result<(), IndexEncodeError> {
1388 if length > options.max_value_arcs {
1389 return Err(encode_error(
1390 IndexEncodeErrorKind::ValueTooLong {
1391 actual: length,
1392 maximum: options.max_value_arcs,
1393 },
1394 position,
1395 component,
1396 ));
1397 }
1398 if let VariableFraming::Fixed(expected) = framing
1399 && length != expected
1400 {
1401 return Err(encode_error(
1402 IndexEncodeErrorKind::FixedLength {
1403 expected,
1404 actual: length,
1405 },
1406 position,
1407 component,
1408 ));
1409 }
1410 match lengths.check(&length) {
1411 ConstraintCheck::Violation => {
1412 return Err(encode_error(
1413 IndexEncodeErrorKind::ConstraintViolation(IndexConstraintViolation::Length {
1414 length,
1415 }),
1416 position,
1417 component,
1418 ));
1419 }
1420 ConstraintCheck::Indeterminate
1421 if options.incomplete_constraints == IncompleteConstraintMode::Reject =>
1422 {
1423 return Err(encode_error(
1424 IndexEncodeErrorKind::IndeterminateConstraint,
1425 position,
1426 component,
1427 ));
1428 }
1429 ConstraintCheck::Allowed | ConstraintCheck::Indeterminate => {}
1430 }
1431
1432 let prefix = usize::from(matches!(framing, VariableFraming::LengthPrefixed));
1433 let component_length = prefix.checked_add(length).ok_or_else(|| {
1434 encode_error(
1435 IndexEncodeErrorKind::ArithmeticOverflow,
1436 position,
1437 component,
1438 )
1439 })?;
1440 push_component(
1441 suffix,
1442 component_length,
1443 options.max_suffix_arcs,
1444 position,
1445 component,
1446 )?;
1447 if prefix != 0 {
1448 suffix.push(u32::try_from(length).map_err(|_| {
1449 encode_error(
1450 IndexEncodeErrorKind::LengthPrefixOverflow { length },
1451 position,
1452 component,
1453 )
1454 })?);
1455 }
1456 suffix.extend(arcs);
1457 Ok(())
1458}
1459
1460fn push_component(
1461 suffix: &[u32],
1462 component_length: usize,
1463 maximum: usize,
1464 position: usize,
1465 component: &IndexComponentSchema,
1466) -> Result<(), IndexEncodeError> {
1467 let actual = suffix.len().checked_add(component_length).ok_or_else(|| {
1468 encode_error(
1469 IndexEncodeErrorKind::ArithmeticOverflow,
1470 position,
1471 component,
1472 )
1473 })?;
1474 if actual > maximum {
1475 return Err(encode_error(
1476 IndexEncodeErrorKind::SuffixTooLong { actual, maximum },
1477 position,
1478 component,
1479 ));
1480 }
1481 Ok(())
1482}
1483
1484fn encode_error(
1485 kind: IndexEncodeErrorKind,
1486 position: usize,
1487 component: &IndexComponentSchema,
1488) -> IndexEncodeError {
1489 IndexEncodeError {
1490 kind,
1491 component_position: Some(position),
1492 component_name: Some(component.name().to_string()),
1493 }
1494}
1495
1496fn encode_whole_error(kind: IndexEncodeErrorKind) -> IndexEncodeError {
1497 IndexEncodeError {
1498 kind,
1499 component_position: None,
1500 component_name: None,
1501 }
1502}