1use core::num::ParseIntError;
2
3use super::strings::PermittedAlphabetError;
4use alloc::{boxed::Box, string::ToString};
5
6use jzon::JsonValue;
7use snafu::Snafu;
8#[cfg(feature = "backtraces")]
9use snafu::{Backtrace, GenerateImplicitData};
10
11use crate::de::Error;
12use crate::types::{constraints::Bounded, variants::Variants, Integer, Tag};
13use crate::Codec;
14
15#[derive(Debug)]
17#[non_exhaustive]
18pub enum CodecDecodeError {
19 Ber(BerDecodeErrorKind),
20 Cer(CerDecodeErrorKind),
21 Der(DerDecodeErrorKind),
22 Uper(UperDecodeErrorKind),
23 Aper(AperDecodeErrorKind),
24 Jer(JerDecodeErrorKind),
25 Oer(OerDecodeErrorKind),
26 Coer(CoerDecodeErrorKind),
27}
28
29macro_rules! impl_from {
30 ($variant:ident, $error_kind:ty) => {
31 impl From<$error_kind> for DecodeError {
32 fn from(error: $error_kind) -> Self {
33 Self::from_codec_kind(CodecDecodeError::$variant(error))
34 }
35 }
36 };
37}
38
39impl_from!(Ber, BerDecodeErrorKind);
41impl_from!(Cer, CerDecodeErrorKind);
42impl_from!(Der, DerDecodeErrorKind);
43impl_from!(Uper, UperDecodeErrorKind);
44impl_from!(Aper, AperDecodeErrorKind);
45impl_from!(Jer, JerDecodeErrorKind);
46impl_from!(Oer, OerDecodeErrorKind);
47impl_from!(Coer, CoerDecodeErrorKind);
48
49impl From<CodecDecodeError> for DecodeError {
50 fn from(error: CodecDecodeError) -> Self {
51 Self::from_codec_kind(error)
52 }
53}
54
55#[derive(Debug)]
136#[allow(clippy::module_name_repetitions)]
137pub struct DecodeError {
138 pub kind: Box<DecodeErrorKind>,
139 pub codec: Codec,
140 #[cfg(feature = "backtraces")]
141 pub backtrace: Backtrace,
142}
143impl core::fmt::Display for DecodeError {
144 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
145 writeln!(f, "Error Kind: {}", self.kind)?;
146 writeln!(f, "Codec: {}", self.codec)?;
147 #[cfg(feature = "backtraces")]
148 write!(f, "\nBacktrace:\n{}", self.backtrace)?;
149 Ok(())
150 }
151}
152
153impl DecodeError {
154 #[must_use]
155 pub fn alphabet_constraint_not_satisfied(reason: PermittedAlphabetError, codec: Codec) -> Self {
156 Self::from_kind(
157 DecodeErrorKind::AlphabetConstraintNotSatisfied { reason },
158 codec,
159 )
160 }
161 #[must_use]
162 pub fn size_constraint_not_satisfied(
163 size: Option<usize>,
164 expected: alloc::string::String,
165 codec: Codec,
166 ) -> Self {
167 Self::from_kind(
168 DecodeErrorKind::SizeConstraintNotSatisfied { size, expected },
169 codec,
170 )
171 }
172 #[must_use]
173 pub fn value_constraint_not_satisfied(
174 value: Integer,
175 expected: Bounded<i128>,
176 codec: Codec,
177 ) -> Self {
178 Self::from_kind(
179 DecodeErrorKind::ValueConstraintNotSatisfied { value, expected },
180 codec,
181 )
182 }
183 #[must_use]
184 pub fn discriminant_value_not_found(discriminant: isize, codec: Codec) -> Self {
185 Self::from_kind(
186 DecodeErrorKind::DiscriminantValueNotFound { discriminant },
187 codec,
188 )
189 }
190 #[must_use]
191 pub fn range_exceeds_platform_width(needed: u32, present: u32, codec: Codec) -> Self {
192 Self::from_kind(
193 DecodeErrorKind::RangeExceedsPlatformWidth { needed, present },
194 codec,
195 )
196 }
197 #[must_use]
198 pub fn fixed_string_conversion_failed(
199 tag: Tag,
200 actual: usize,
201 expected: usize,
202 codec: Codec,
203 ) -> Self {
204 Self::from_kind(
205 DecodeErrorKind::FixedStringConversionFailed {
206 tag,
207 actual,
208 expected,
209 },
210 codec,
211 )
212 }
213 #[must_use]
214 pub fn incorrect_item_number_in_sequence(expected: usize, actual: usize, codec: Codec) -> Self {
215 Self::from_kind(
216 DecodeErrorKind::IncorrectItemNumberInSequence { expected, actual },
217 codec,
218 )
219 }
220 #[must_use]
221 pub fn integer_overflow(max_width: u32, codec: Codec) -> Self {
222 Self::from_kind(DecodeErrorKind::IntegerOverflow { max_width }, codec)
223 }
224 #[must_use]
225 pub fn integer_type_conversion_failed(msg: alloc::string::String, codec: Codec) -> Self {
226 Self::from_kind(DecodeErrorKind::IntegerTypeConversionFailed { msg }, codec)
227 }
228 #[must_use]
229 pub fn invalid_bit_string(bits: u8, codec: Codec) -> Self {
230 Self::from_kind(DecodeErrorKind::InvalidBitString { bits }, codec)
231 }
232 #[must_use]
233 pub fn missing_tag_class_or_value_in_sequence_or_set(
234 class: crate::types::Class,
235 value: u32,
236 codec: Codec,
237 ) -> Self {
238 Self::from_kind(
239 DecodeErrorKind::MissingTagClassOrValueInSequenceOrSet { class, value },
240 codec,
241 )
242 }
243
244 #[must_use]
245 pub fn type_not_extensible(codec: Codec) -> Self {
246 Self::from_kind(DecodeErrorKind::TypeNotExtensible, codec)
247 }
248 #[must_use]
249 pub fn parser_fail(msg: alloc::string::String, codec: Codec) -> Self {
250 DecodeError::from_kind(DecodeErrorKind::Parser { msg }, codec)
251 }
252
253 #[must_use]
254 pub fn required_extension_not_present(tag: Tag, codec: Codec) -> Self {
255 Self::from_kind(DecodeErrorKind::RequiredExtensionNotPresent { tag }, codec)
256 }
257 #[must_use]
258 pub fn extension_present_but_not_required(tag: crate::types::Tag, codec: Codec) -> Self {
259 Self::from_kind(
260 DecodeErrorKind::ExtensionPresentButNotRequired { tag },
261 codec,
262 )
263 }
264 #[must_use]
265 pub fn enumeration_index_not_found(index: usize, extended_list: bool, codec: Codec) -> Self {
266 Self::from_kind(
267 DecodeErrorKind::EnumerationIndexNotFound {
268 index,
269 extended_list,
270 },
271 codec,
272 )
273 }
274 #[must_use]
275 pub fn choice_index_exceeds_platform_width(needed: u32, present: u64, codec: Codec) -> Self {
276 Self::from_kind(
277 DecodeErrorKind::ChoiceIndexExceedsPlatformWidth { needed, present },
278 codec,
279 )
280 }
281 #[must_use]
282 pub fn length_exceeds_platform_width(msg: alloc::string::String, codec: Codec) -> Self {
283 Self::from_kind(DecodeErrorKind::LengthExceedsPlatformWidth { msg }, codec)
284 }
285
286 #[must_use]
287 pub fn choice_index_not_found(index: usize, variants: Variants, codec: Codec) -> Self {
288 Self::from_kind(
289 DecodeErrorKind::ChoiceIndexNotFound { index, variants },
290 codec,
291 )
292 }
293 #[must_use]
294 pub fn string_conversion_failed(tag: Tag, msg: alloc::string::String, codec: Codec) -> Self {
295 Self::from_kind(DecodeErrorKind::StringConversionFailed { tag, msg }, codec)
296 }
297 #[must_use]
298 pub fn unexpected_extra_data(length: usize, codec: Codec) -> Self {
299 Self::from_kind(DecodeErrorKind::UnexpectedExtraData { length }, codec)
300 }
301 #[must_use]
302 pub fn unexpected_empty_input(codec: Codec) -> Self {
303 Self::from_kind(DecodeErrorKind::UnexpectedEmptyInput, codec)
304 }
305
306 pub fn assert_length(
307 expected: usize,
308 actual: usize,
309 codec: Codec,
310 ) -> core::result::Result<(), DecodeError> {
311 if expected == actual {
312 Ok(())
313 } else {
314 Err(DecodeError::from_kind(
315 DecodeErrorKind::MismatchedLength { expected, actual },
316 codec,
317 ))
318 }
319 }
320
321 pub fn map_nom_err<T: core::fmt::Debug>(
322 error: nom::Err<nom::error::Error<T>>,
323 codec: Codec,
324 ) -> DecodeError {
325 let msg = match error {
326 nom::Err::Incomplete(needed) => return DecodeError::incomplete(needed, codec),
327 err => alloc::format!("Parsing Failure: {err}"),
328 };
329 DecodeError::parser_fail(msg, codec)
330 }
331 #[must_use]
332 pub fn from_kind(kind: DecodeErrorKind, codec: Codec) -> Self {
333 Self {
334 kind: Box::new(kind),
335 codec,
336 #[cfg(feature = "backtraces")]
337 backtrace: Backtrace::generate(),
338 }
339 }
340 #[must_use]
341 fn from_codec_kind(inner: CodecDecodeError) -> Self {
342 let codec = match inner {
343 CodecDecodeError::Ber(_) => crate::Codec::Ber,
344 CodecDecodeError::Cer(_) => crate::Codec::Cer,
345 CodecDecodeError::Der(_) => crate::Codec::Der,
346 CodecDecodeError::Uper(_) => crate::Codec::Uper,
347 CodecDecodeError::Aper(_) => crate::Codec::Aper,
348 CodecDecodeError::Jer(_) => crate::Codec::Jer,
349 CodecDecodeError::Oer(_) => crate::Codec::Oer,
350 CodecDecodeError::Coer(_) => crate::Codec::Coer,
351 };
352 Self {
353 kind: Box::new(DecodeErrorKind::CodecSpecific { inner }),
354 codec,
355 #[cfg(feature = "backtraces")]
356 backtrace: Backtrace::generate(),
357 }
358 }
359}
360
361#[derive(Snafu)]
363#[snafu(visibility(pub))]
364#[derive(Debug)]
365#[non_exhaustive]
366pub enum DecodeErrorKind {
367 #[snafu(display("Alphabet constraint not satisfied {}", reason))]
368 AlphabetConstraintNotSatisfied { reason: PermittedAlphabetError },
369 #[snafu(display("Size constraint not satisfied: expected: {expected}; actual: {size:?}"))]
370 SizeConstraintNotSatisfied {
371 size: Option<usize>,
373 expected: alloc::string::String,
375 },
376 #[snafu(display("Value constraint not satisfied: expected: {expected}; actual: {value}"))]
377 ValueConstraintNotSatisfied {
378 value: Integer,
380 expected: Bounded<i128>,
382 },
383 #[snafu(display("Wrapped codec-specific decode error"))]
384 CodecSpecific { inner: CodecDecodeError },
385
386 #[snafu(display(
387 "Enumeration index '{}' did not match any variant. Extended list: {}",
388 index,
389 extended_list
390 ))]
391 EnumerationIndexNotFound {
392 index: usize,
394 extended_list: bool,
396 },
397 #[snafu(display("choice index '{index}' did not match any variant"))]
398 ChoiceIndexNotFound {
399 index: usize,
401 variants: Variants,
403 },
404 #[snafu(display("integer range larger than possible to address on this platform. needed: {needed} present: {present}"))]
405 ChoiceIndexExceedsPlatformWidth {
406 needed: u32,
408 present: u64,
410 },
411 #[snafu(display("Custom: {}", msg))]
412 Custom {
413 msg: alloc::string::String,
415 },
416 #[snafu(display("Discriminant value '{}' did not match any variant", discriminant))]
417 DiscriminantValueNotFound {
418 discriminant: isize,
420 },
421 #[snafu(display("Duplicate field for `{}`", name))]
422 DuplicateField {
423 name: &'static str,
425 },
426 #[snafu(display("Expected maximum of {} items", length))]
427 ExceedsMaxLength {
428 length: num_bigint::BigUint,
430 },
431 #[snafu(display(
433 "Length of the incoming data is either incorrect or your device is up by miracle."
434 ))]
435 LengthExceedsPlatformWidth { msg: alloc::string::String },
436 #[snafu(display("Error when decoding field `{}`: {}", name, nested))]
437 FieldError {
438 name: &'static str,
440 nested: Box<DecodeError>,
441 },
442 #[snafu(display("Need more BITS to continue: ({:?}).", needed))]
446 Incomplete {
447 needed: nom::Needed,
449 },
450 #[snafu(display(
451 "Invalid item number in Sequence: expected {}, actual {}",
452 expected,
453 actual
454 ))]
455 IncorrectItemNumberInSequence {
456 expected: usize,
458 actual: usize,
460 },
461 #[snafu(display("Actual integer larger than expected {} bits", max_width))]
462 IntegerOverflow {
463 max_width: u32,
465 },
466 #[snafu(display("Failed to cast integer to another integer type: {msg} "))]
467 IntegerTypeConversionFailed { msg: alloc::string::String },
468 #[snafu(display("BitString contains an invalid amount of unused bits: {}", bits))]
469 InvalidBitString {
470 bits: u8,
472 },
473 #[snafu(display(
475 "Bool value is not `0` or `0xFF` as canonical requires. Actual: {}",
476 value
477 ))]
478 InvalidBool { value: u8 },
479 #[snafu(display("Length of Length cannot be zero"))]
481 ZeroLengthOfLength,
482 #[snafu(display("Expected {:?} bytes, actual length: {:?}", expected, actual))]
484 MismatchedLength {
485 expected: usize,
487 actual: usize,
489 },
490
491 #[snafu(display("Missing field `{}`", name))]
492 MissingField {
493 name: &'static str,
495 },
496 #[snafu(display("Expected class: {}, value: {} in sequence or set Missing tag class or value in sequence or set", class, value))]
497 MissingTagClassOrValueInSequenceOrSet {
498 class: crate::types::Class,
500 value: u32,
501 },
502
503 #[snafu(display("integer range larger than possible to address on this platform. needed: {needed} present: {present}"))]
504 RangeExceedsPlatformWidth {
505 needed: u32,
507 present: u32,
509 },
510 #[snafu(display("Extension with class `{}` and tag `{}` required, but not present", tag.class, tag.value))]
511 RequiredExtensionNotPresent { tag: crate::types::Tag },
512 #[snafu(display("Extension {} present but but not required", tag.class))]
513 ExtensionPresentButNotRequired { tag: crate::types::Tag },
514 #[snafu(display("Error in Parser: {}", msg))]
515 Parser {
516 msg: alloc::string::String,
518 },
519 #[snafu(display(
520 "Failed to convert byte array into valid ASN.1 string. String type as tag: {} Error: {}",
521 tag,
522 msg
523 ))]
524 StringConversionFailed {
525 tag: Tag,
527 msg: alloc::string::String,
529 },
530 #[snafu(display(
531 "Failed to convert byte array into valid fixed-sized ASN.1 string. String type as tag: {}, actual: {}, expected: {}",
532 tag,
533 actual,
534 expected
535 ))]
536 FixedStringConversionFailed {
537 tag: Tag,
539 expected: usize,
541 actual: usize,
543 },
544 #[snafu(display("No valid choice for `{}`", name))]
545 NoValidChoice {
546 name: &'static str,
548 },
549
550 #[snafu(display("Attempted to decode extension on non-extensible type"))]
551 TypeNotExtensible,
552 #[snafu(display("Unexpected extra data found: length `{}` bytes", length))]
554 UnexpectedExtraData {
555 length: usize,
557 },
558 #[snafu(display("Unknown field with index {} and tag {}", index, tag))]
559 UnknownField { index: usize, tag: Tag },
560 #[snafu(display("SEQUENCE has at least one required field, but no input provided"))]
561 UnexpectedEmptyInput,
562}
563
564#[derive(Snafu, Debug)]
566#[snafu(visibility(pub))]
567#[non_exhaustive]
568pub enum BerDecodeErrorKind {
569 #[snafu(display("Indefinite length encountered but not allowed."))]
570 IndefiniteLengthNotAllowed,
571 #[snafu(display("Invalid constructed identifier for ASN.1 value: not primitive."))]
572 InvalidConstructedIdentifier,
573 #[snafu(display("Invalid date string: {}", msg))]
575 InvalidDate { msg: alloc::string::String },
576 #[snafu(display("Invalid object identifier with missing or corrupt root nodes."))]
577 InvalidObjectIdentifier,
578 #[snafu(display("Expected {:?} tag, actual tag: {:?}", expected, actual))]
580 MismatchedTag {
581 expected: Tag,
583 actual: Tag,
585 },
586}
587
588impl BerDecodeErrorKind {
589 #[must_use]
590 pub fn invalid_date(msg: alloc::string::String) -> CodecDecodeError {
591 CodecDecodeError::Ber(Self::InvalidDate { msg })
592 }
593 pub fn assert_tag(expected: Tag, actual: Tag) -> core::result::Result<(), DecodeError> {
594 if expected == actual {
595 Ok(())
596 } else {
597 Err(BerDecodeErrorKind::MismatchedTag { expected, actual }.into())
598 }
599 }
600}
601#[derive(Snafu, Debug)]
604#[snafu(visibility(pub))]
605#[non_exhaustive]
606pub enum CerDecodeErrorKind {}
607
608#[derive(Snafu, Debug)]
610#[snafu(visibility(pub))]
611#[non_exhaustive]
612pub enum DerDecodeErrorKind {
613 #[snafu(display("Constructed encoding encountered but not allowed."))]
614 ConstructedEncodingNotAllowed,
615}
616
617#[derive(Snafu, Debug)]
619#[snafu(visibility(pub))]
620#[non_exhaustive]
621pub enum JerDecodeErrorKind {
622 #[snafu(display("Unexpected end of input while decoding JER JSON."))]
623 EndOfInput {},
624 #[snafu(display(
625 "Found mismatching JSON value. Expected type {}. Found value {}.",
626 needed,
627 found
628 ))]
629 TypeMismatch {
630 needed: &'static str,
631 found: alloc::string::String,
632 },
633 #[snafu(display("Found invalid byte in bit string. {parse_int_err}"))]
634 InvalidJerBitstring { parse_int_err: ParseIntError },
635 #[snafu(display("Found invalid character in octet string."))]
636 InvalidJerOctetString {},
637 #[snafu(display("Failed to construct OID from value {value}",))]
638 InvalidOIDString { value: JsonValue },
639 #[snafu(display("Found invalid enumerated discriminant {discriminant}",))]
640 InvalidEnumDiscriminant { discriminant: alloc::string::String },
641}
642
643impl JerDecodeErrorKind {
644 pub fn eoi() -> CodecDecodeError {
645 CodecDecodeError::Jer(JerDecodeErrorKind::EndOfInput {})
646 }
647}
648
649#[derive(Snafu, Debug)]
652#[snafu(visibility(pub))]
653#[non_exhaustive]
654pub enum UperDecodeErrorKind {}
655
656#[derive(Snafu, Debug)]
659#[snafu(visibility(pub))]
660#[non_exhaustive]
661pub enum AperDecodeErrorKind {}
662
663#[derive(Snafu, Debug)]
664#[snafu(visibility(pub))]
665#[non_exhaustive]
666pub enum OerDecodeErrorKind {
667 #[snafu(display("Invalid tag class when decoding choice: actual {:?}", class))]
669 InvalidTagClassOnChoice {
670 class: u8,
672 },
673 #[snafu(display("Invalid tag number when decoding Choice. Value: {value}"))]
674 InvalidTagNumberOnChoice { value: u32 },
675 #[snafu(display(
676 "Tag not found from the variants of the platform when decoding Choice. Tag: {value}, extensible status: {is_extensible}"
677 ))]
678 InvalidTagVariantOnChoice { value: Tag, is_extensible: bool },
679
680 InvalidExtensionHeader {
681 msg: alloc::string::String,
683 },
684 #[snafu(display("Invalid BitString: {msg}"))]
685 InvalidOerBitString {
686 msg: alloc::string::String,
688 },
689}
690
691impl OerDecodeErrorKind {
692 #[must_use]
693 pub fn invalid_tag_number_on_choice(value: u32) -> DecodeError {
694 CodecDecodeError::Oer(Self::InvalidTagNumberOnChoice { value }).into()
695 }
696 #[must_use]
697 pub fn invalid_tag_variant_on_choice(value: Tag, is_extensible: bool) -> DecodeError {
698 CodecDecodeError::Oer(Self::InvalidTagVariantOnChoice {
699 value,
700 is_extensible,
701 })
702 .into()
703 }
704
705 #[must_use]
706 pub fn invalid_extension_header(msg: alloc::string::String) -> DecodeError {
707 CodecDecodeError::Oer(Self::InvalidExtensionHeader { msg }).into()
708 }
709 #[must_use]
710 pub fn invalid_bit_string(msg: alloc::string::String) -> DecodeError {
711 CodecDecodeError::Oer(Self::InvalidOerBitString { msg }).into()
712 }
713}
714
715#[derive(Snafu, Debug)]
716#[snafu(visibility(pub))]
717#[non_exhaustive]
718pub enum CoerDecodeErrorKind {
719 #[snafu(display("Invalid Canonical Octet Encoding, not encoded as the smallest possible number of octets: {msg}"))]
720 NotValidCanonicalEncoding { msg: alloc::string::String },
721}
722
723impl crate::de::Error for DecodeError {
724 fn custom<D: core::fmt::Display>(msg: D, codec: Codec) -> Self {
725 Self::from_kind(
726 DecodeErrorKind::Custom {
727 msg: msg.to_string(),
728 },
729 codec,
730 )
731 }
732 fn incomplete(needed: nom::Needed, codec: Codec) -> Self {
733 Self::from_kind(DecodeErrorKind::Incomplete { needed }, codec)
734 }
735
736 fn exceeds_max_length(length: num_bigint::BigUint, codec: Codec) -> Self {
737 Self::from_kind(DecodeErrorKind::ExceedsMaxLength { length }, codec)
738 }
739
740 fn missing_field(name: &'static str, codec: Codec) -> Self {
741 Self::from_kind(DecodeErrorKind::MissingField { name }, codec)
742 }
743
744 fn no_valid_choice(name: &'static str, codec: Codec) -> Self {
745 Self::from_kind(DecodeErrorKind::NoValidChoice { name }, codec)
746 }
747
748 fn field_error(name: &'static str, nested: DecodeError, codec: Codec) -> Self {
749 Self::from_kind(
750 DecodeErrorKind::FieldError {
751 name,
752 nested: Box::new(nested),
753 },
754 codec,
755 )
756 }
757
758 fn duplicate_field(name: &'static str, codec: Codec) -> Self {
759 Self::from_kind(DecodeErrorKind::DuplicateField { name }, codec)
760 }
761 fn unknown_field(index: usize, tag: Tag, codec: Codec) -> Self {
762 Self::from_kind(DecodeErrorKind::UnknownField { index, tag }, codec)
763 }
764}
765
766#[cfg(test)]
767mod tests {
768 use crate::prelude::*;
769 #[test]
770 fn test_ber_decode_date() {
771 use crate::error::{DecodeError, DecodeErrorKind};
772 let data = [
774 23, 17, 50, 51, 48, 49, 50, 50, 49, 51, 48, 48, 48, 48, 45, 48, 53, 48, 90,
775 ];
776 let result = crate::ber::decode::<UtcTime>(&data);
777 match result {
778 Err(DecodeError { kind, .. }) => {
779 if let DecodeErrorKind::CodecSpecific {
780 inner:
781 crate::error::CodecDecodeError::Ber(
782 crate::error::BerDecodeErrorKind::InvalidDate { msg },
783 ),
784 ..
785 } = *kind
786 {
787 assert_eq!(msg, "230122130000-050Z");
788 } else {
789 panic!("Unexpected error kind: {kind}");
791 }
792 }
793 Ok(_) => panic!("Expected error"),
794 }
795 }
796 #[test]
797 fn test_uper_missing_choice_index() {
798 use crate as rasn;
799 use crate::error::{DecodeError, DecodeErrorKind};
800 use crate::Codec;
801 #[derive(AsnType, Decode, Debug, PartialEq)]
802 #[rasn(choice, automatic_tags)]
803 enum MyChoice {
804 Normal(Integer),
805 High(Integer),
806 Medium(Integer),
807 }
808 let data = [192, 128, 83, 64];
810 let result = Codec::Uper.decode_from_binary::<MyChoice>(&data);
811 match result {
812 Ok(_) => {
813 panic!("Unexpected OK!");
814 }
815 Err(DecodeError { kind, .. }) => {
816 if let DecodeErrorKind::ChoiceIndexNotFound { index, .. } = *kind {
817 assert_eq!(index, 3);
818 } else {
819 panic!("Unexpected error kind: {kind}");
821 }
822 }
823 }
824 }
825}