use core::num::ParseIntError;
use super::strings::PermittedAlphabetError;
use alloc::{boxed::Box, string::ToString};
use snafu::Snafu;
#[cfg(feature = "backtraces")]
use snafu::{Backtrace, GenerateImplicitData};
use crate::Codec;
use crate::de::Error;
use crate::types::{Tag, constraints::Bounded, variants::Variants};
use num_bigint::BigInt;
#[derive(Debug)]
#[non_exhaustive]
#[allow(missing_docs)]
pub enum CodecDecodeError {
Ber(BerDecodeErrorKind),
Cer(CerDecodeErrorKind),
Der(DerDecodeErrorKind),
Uper(UperDecodeErrorKind),
Aper(AperDecodeErrorKind),
Jer(JerDecodeErrorKind),
Oer(OerDecodeErrorKind),
Coer(CoerDecodeErrorKind),
Xer(XerDecodeErrorKind),
}
impl core::fmt::Display for CodecDecodeError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
CodecDecodeError::Ber(kind) => write!(f, "BER decoding error: {kind}"),
CodecDecodeError::Cer(kind) => write!(f, "CER decoding error: {kind}"),
CodecDecodeError::Der(kind) => write!(f, "DER decoding error: {kind}"),
CodecDecodeError::Uper(kind) => write!(f, "UPER decoding error: {kind}"),
CodecDecodeError::Aper(kind) => write!(f, "APER decoding error: {kind}"),
CodecDecodeError::Jer(kind) => write!(f, "JER decoding error: {kind}"),
CodecDecodeError::Oer(kind) => write!(f, "OER decoding error: {kind}"),
CodecDecodeError::Coer(kind) => write!(f, "COER decoding error: {kind}"),
CodecDecodeError::Xer(kind) => write!(f, "XER decoding error: {kind}"),
}
}
}
macro_rules! impl_from {
($variant:ident, $error_kind:ty) => {
impl From<$error_kind> for DecodeError {
fn from(error: $error_kind) -> Self {
Self::from_codec_kind(CodecDecodeError::$variant(error))
}
}
};
}
impl_from!(Ber, BerDecodeErrorKind);
impl_from!(Cer, CerDecodeErrorKind);
impl_from!(Der, DerDecodeErrorKind);
impl_from!(Uper, UperDecodeErrorKind);
impl_from!(Aper, AperDecodeErrorKind);
impl_from!(Jer, JerDecodeErrorKind);
impl_from!(Oer, OerDecodeErrorKind);
impl_from!(Coer, CoerDecodeErrorKind);
impl_from!(Xer, XerDecodeErrorKind);
impl From<CodecDecodeError> for DecodeError {
fn from(error: CodecDecodeError) -> Self {
Self::from_codec_kind(error)
}
}
#[derive(Debug)]
#[allow(clippy::module_name_repetitions)]
pub struct DecodeError {
pub kind: Box<DecodeErrorKind>,
pub codec: Codec,
#[cfg(feature = "backtraces")]
pub backtrace: Backtrace,
}
impl core::fmt::Display for DecodeError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{} (Codec: {})", self.kind, self.codec)?;
#[cfg(feature = "backtraces")]
write!(f, "\n\nBacktrace:\n{}", self.backtrace)?;
Ok(())
}
}
impl DecodeError {
fn eof(codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::Eof, codec)
}
#[must_use]
pub fn permitted_alphabet_error(reason: PermittedAlphabetError, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::PermittedAlphabetError { reason }, codec)
}
#[must_use]
pub fn size_constraint_not_satisfied(
size: Option<usize>,
expected: alloc::string::String,
codec: Codec,
) -> Self {
Self::from_kind(
DecodeErrorKind::SizeConstraintNotSatisfied { size, expected },
codec,
)
}
#[must_use]
pub fn value_constraint_not_satisfied(
value: BigInt,
expected: Bounded<i128>,
codec: Codec,
) -> Self {
Self::from_kind(
DecodeErrorKind::ValueConstraintNotSatisfied { value, expected },
codec,
)
}
#[must_use]
pub fn inner_subtype_constraint_not_satisfied(
reason: super::InnerSubtypeConstraintError,
codec: Codec,
) -> Self {
Self::from_kind(
DecodeErrorKind::InnerSubtypeConstraintNotSatisfied { reason },
codec,
)
}
#[must_use]
pub fn discriminant_value_not_found(discriminant: isize, codec: Codec) -> Self {
Self::from_kind(
DecodeErrorKind::DiscriminantValueNotFound { discriminant },
codec,
)
}
#[must_use]
pub fn range_exceeds_platform_width(needed: u32, present: u32, codec: Codec) -> Self {
Self::from_kind(
DecodeErrorKind::RangeExceedsPlatformWidth { needed, present },
codec,
)
}
#[must_use]
pub fn fixed_string_conversion_failed(
tag: Tag,
actual: usize,
expected: usize,
codec: Codec,
) -> Self {
Self::from_kind(
DecodeErrorKind::FixedStringConversionFailed {
tag,
actual,
expected,
},
codec,
)
}
#[must_use]
pub fn incorrect_item_number_in_sequence(expected: usize, actual: usize, codec: Codec) -> Self {
Self::from_kind(
DecodeErrorKind::IncorrectItemNumberInSequence { expected, actual },
codec,
)
}
#[must_use]
pub fn integer_overflow(max_width: u32, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::IntegerOverflow { max_width }, codec)
}
#[must_use]
pub fn integer_type_conversion_failed(msg: alloc::string::String, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::IntegerTypeConversionFailed { msg }, codec)
}
#[must_use]
pub fn invalid_bit_string(bits: u8, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::InvalidBitString { bits }, codec)
}
#[must_use]
pub fn missing_tag_class_or_value_in_sequence_or_set(
class: crate::types::Class,
value: u32,
codec: Codec,
) -> Self {
Self::from_kind(
DecodeErrorKind::MissingTagClassOrValueInSequenceOrSet { class, value },
codec,
)
}
#[must_use]
pub fn type_not_extensible(codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::TypeNotExtensible, codec)
}
#[must_use]
pub fn parser_fail(msg: alloc::string::String, codec: Codec) -> Self {
DecodeError::from_kind(DecodeErrorKind::Parser { msg }, codec)
}
#[must_use]
pub fn real_not_supported(codec: Codec) -> Self {
DecodeError::from_kind(DecodeErrorKind::RealNotSupported, codec)
}
#[must_use]
pub fn required_extension_not_present(tag: Tag, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::RequiredExtensionNotPresent { tag }, codec)
}
#[must_use]
pub fn enumeration_index_not_found(index: usize, extended_list: bool, codec: Codec) -> Self {
Self::from_kind(
DecodeErrorKind::EnumerationIndexNotFound {
index,
extended_list,
},
codec,
)
}
#[must_use]
pub fn choice_index_exceeds_platform_width(
needed: u32,
present: DecodeError,
codec: Codec,
) -> Self {
Self::from_kind(
DecodeErrorKind::ChoiceIndexExceedsPlatformWidth { needed, present },
codec,
)
}
#[must_use]
pub fn length_exceeds_platform_width(msg: alloc::string::String, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::LengthExceedsPlatformWidth { msg }, codec)
}
#[must_use]
pub fn choice_index_not_found(index: usize, variants: Variants, codec: Codec) -> Self {
Self::from_kind(
DecodeErrorKind::ChoiceIndexNotFound { index, variants },
codec,
)
}
#[must_use]
pub fn string_conversion_failed(tag: Tag, msg: alloc::string::String, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::StringConversionFailed { tag, msg }, codec)
}
#[must_use]
pub fn unexpected_extra_data(length: usize, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::UnexpectedExtraData { length }, codec)
}
#[must_use]
pub fn unexpected_empty_input(codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::UnexpectedEmptyInput, codec)
}
pub fn assert_length(
expected: usize,
actual: usize,
codec: Codec,
) -> core::result::Result<(), DecodeError> {
if expected == actual {
Ok(())
} else {
Err(DecodeError::from_kind(
DecodeErrorKind::MismatchedLength { expected, actual },
codec,
))
}
}
pub(crate) fn map_nom_err<T: core::fmt::Debug>(
error: nom::Err<nom::error::Error<T>>,
codec: Codec,
) -> DecodeError {
match error {
nom::Err::Incomplete(needed) => DecodeError::incomplete(needed, codec),
nom::Err::Failure(e) | nom::Err::Error(e) => {
if e.code == nom::error::ErrorKind::Eof {
DecodeError::eof(codec)
} else {
DecodeError::parser_fail(alloc::format!("Parsing Failure: {e:?}"), codec)
}
}
}
}
#[must_use]
pub fn from_kind(kind: DecodeErrorKind, codec: Codec) -> Self {
Self {
kind: Box::new(kind),
codec,
#[cfg(feature = "backtraces")]
backtrace: Backtrace::generate(),
}
}
#[must_use]
fn from_codec_kind(inner: CodecDecodeError) -> Self {
let codec = match inner {
CodecDecodeError::Ber(_) => crate::Codec::Ber,
#[allow(unreachable_patterns)]
CodecDecodeError::Cer(_) => crate::Codec::Cer,
CodecDecodeError::Der(_) => crate::Codec::Der,
#[allow(unreachable_patterns)]
CodecDecodeError::Uper(_) => crate::Codec::Uper,
#[allow(unreachable_patterns)]
CodecDecodeError::Aper(_) => crate::Codec::Aper,
CodecDecodeError::Jer(_) => crate::Codec::Jer,
CodecDecodeError::Oer(_) => crate::Codec::Oer,
CodecDecodeError::Coer(_) => crate::Codec::Coer,
CodecDecodeError::Xer(_) => crate::Codec::Xer,
};
Self {
kind: Box::new(DecodeErrorKind::CodecSpecific { inner }),
codec,
#[cfg(feature = "backtraces")]
backtrace: Backtrace::generate(),
}
}
#[must_use]
pub fn matches_root_cause<F>(&self, predicate: F) -> bool
where
F: Fn(&DecodeErrorKind) -> bool,
{
let mut root = self;
while let DecodeErrorKind::FieldError { nested, .. } = &*root.kind {
root = &**nested;
}
predicate(&root.kind)
}
}
impl core::error::Error for DecodeError {}
#[derive(Snafu)]
#[snafu(visibility(pub))]
#[derive(Debug)]
#[non_exhaustive]
pub enum DecodeErrorKind {
#[snafu(display("Alphabet constraint not satisfied {}", reason))]
PermittedAlphabetError {
reason: PermittedAlphabetError,
},
#[snafu(display("Size constraint not satisfied: expected: {expected}; actual: {size:?}"))]
SizeConstraintNotSatisfied {
size: Option<usize>,
expected: alloc::string::String,
},
#[snafu(display("Value constraint not satisfied: expected: {expected}; actual: {value}"))]
ValueConstraintNotSatisfied {
value: BigInt,
expected: Bounded<i128>,
},
#[snafu(display("Inner subtype constraint not satisfied: {reason}"))]
InnerSubtypeConstraintNotSatisfied {
reason: super::InnerSubtypeConstraintError,
},
#[snafu(display("{inner}"))]
CodecSpecific {
inner: CodecDecodeError,
},
#[snafu(display(
"Enumeration index {} did not match any variant. Extended list checked: {}",
index,
extended_list
))]
EnumerationIndexNotFound {
index: usize,
extended_list: bool,
},
#[snafu(display("Choice index {index} did not match any variant"))]
ChoiceIndexNotFound {
index: usize,
variants: Variants,
},
#[snafu(display(
"Choice index exceeds platform index width. Needed {needed} bytes, present: {present}"
))]
ChoiceIndexExceedsPlatformWidth {
needed: u32,
present: DecodeError,
},
#[snafu(display("Custom error: {}", msg))]
Custom {
msg: alloc::string::String,
},
#[snafu(display("Discriminant value {} did not match any variant", discriminant))]
DiscriminantValueNotFound {
discriminant: isize,
},
#[snafu(display("Duplicate field for `{}`", name))]
DuplicateField {
name: &'static str,
},
#[snafu(display("Expected maximum of {} items", length))]
ExceedsMaxLength {
length: num_bigint::BigUint,
},
#[snafu(display("Length of the data exceeds platform address width"))]
LengthExceedsPlatformWidth {
msg: alloc::string::String,
},
#[snafu(display("Error when decoding field `{}`: {}", name, nested))]
FieldError {
name: &'static str,
nested: Box<DecodeError>,
},
#[snafu(display("Need more data to continue: {:?}", needed))]
Incomplete {
needed: nom::Needed,
},
#[snafu(display("Unexpected EOF when decoding"))]
Eof,
#[snafu(display(
"Invalid item number in Sequence: expected: {}; actual: {}",
expected,
actual
))]
IncorrectItemNumberInSequence {
expected: usize,
actual: usize,
},
#[snafu(display("Actual integer larger than expected {} bits", max_width))]
IntegerOverflow {
max_width: u32,
},
#[snafu(display("Failed to cast integer to another integer type: {msg} "))]
IntegerTypeConversionFailed {
msg: alloc::string::String,
},
#[snafu(display("Invalid real encoding"))]
InvalidRealEncoding,
#[snafu(display("Decoder doesn't support `REAL` type"))]
RealNotSupported,
#[snafu(display("BitString contains an invalid amount of unused bits: {}", bits))]
InvalidBitString {
bits: u8,
},
#[snafu(display(
"Bool value is not `0` or `0xFF` as canonical requires. Actual: {}",
value
))]
InvalidBool {
value: u8,
},
#[snafu(display("Length of Length cannot be zero"))]
ZeroLengthOfLength,
#[snafu(display("Expected {} bytes, actual length was {} bytes", expected, actual))]
MismatchedLength {
expected: usize,
actual: usize,
},
#[snafu(display("Missing field `{}`", name))]
MissingField {
name: &'static str,
},
#[snafu(display(
"Expected class: {}, value: {} in sequence or set Missing tag class or value in sequence or set",
class,
value
))]
MissingTagClassOrValueInSequenceOrSet {
class: crate::types::Class,
value: u32,
},
#[snafu(display(
"Integer range larger than possible to address on this platform. needed: {needed} present: {present}"
))]
RangeExceedsPlatformWidth {
needed: u32,
present: u32,
},
#[snafu(display("Extension with class `{}` and tag `{}` required, but not present", tag.class, tag.value))]
RequiredExtensionNotPresent {
tag: crate::types::Tag,
},
#[snafu(display("Error in Parser: {}", msg))]
Parser {
msg: alloc::string::String,
},
#[snafu(display(
"Failed to convert byte array into valid ASN.1 string. String type as tag: {} Error: {}",
tag,
msg
))]
StringConversionFailed {
tag: Tag,
msg: alloc::string::String,
},
#[snafu(display(
"Failed to convert byte array into valid fixed-sized ASN.1 string. String type as tag: {}, actual: {}, expected: {}",
tag,
actual,
expected
))]
FixedStringConversionFailed {
tag: Tag,
expected: usize,
actual: usize,
},
#[snafu(display("No valid choice for `{}`", name))]
NoValidChoice {
name: &'static str,
},
#[snafu(display("Attempted to decode extension on non-extensible type"))]
TypeNotExtensible,
#[snafu(display("Unexpected extra data found: length `{}` bytes", length))]
UnexpectedExtraData {
length: usize,
},
#[snafu(display("Unknown field with index {} and tag {}", index, tag))]
UnknownField {
index: usize,
tag: Tag,
},
#[snafu(display("No input was provided where expected in the given SEQUENCE or INTEGER type"))]
UnexpectedEmptyInput,
#[snafu(display("Exceeded maximum parse depth"))]
ExceedsMaxParseDepth,
}
#[derive(Snafu, Debug)]
#[snafu(visibility(pub))]
#[non_exhaustive]
pub enum BerDecodeErrorKind {
#[snafu(display("Indefinite length encountered but not allowed"))]
IndefiniteLengthNotAllowed,
#[snafu(display("Invalid constructed identifier for ASN.1 value: not primitive"))]
InvalidConstructedIdentifier,
#[snafu(display("Invalid date string: {}", msg))]
InvalidDate {
msg: alloc::string::String,
},
#[snafu(display("Invalid object identifier with missing or corrupt root nodes"))]
InvalidObjectIdentifier,
#[snafu(display("Expected {:?} tag, actual tag: {:?}", expected, actual))]
MismatchedTag {
expected: Tag,
actual: Tag,
},
}
impl BerDecodeErrorKind {
#[must_use]
pub fn invalid_date(msg: alloc::string::String) -> CodecDecodeError {
CodecDecodeError::Ber(Self::InvalidDate { msg })
}
pub fn assert_tag(expected: Tag, actual: Tag) -> core::result::Result<(), DecodeError> {
if expected == actual {
Ok(())
} else {
Err(BerDecodeErrorKind::MismatchedTag { expected, actual }.into())
}
}
}
#[derive(Snafu, Debug)]
#[snafu(visibility(pub))]
#[non_exhaustive]
pub enum CerDecodeErrorKind {}
#[derive(Snafu, Debug)]
#[snafu(visibility(pub))]
#[non_exhaustive]
pub enum DerDecodeErrorKind {
#[snafu(display("Constructed encoding encountered but not allowed"))]
ConstructedEncodingNotAllowed,
}
#[derive(Snafu, Debug)]
#[snafu(visibility(pub))]
#[non_exhaustive]
pub enum JerDecodeErrorKind {
#[snafu(display("Unexpected end of input while decoding JER"))]
EndOfInput {},
#[snafu(display(
"Found mismatching JSON value. Expected type: {}. Found value: {}",
needed,
found
))]
TypeMismatch {
needed: &'static str,
found: alloc::string::String,
},
#[snafu(display("Found invalid byte in bit string: {parse_int_err}"))]
InvalidJerBitstring {
parse_int_err: ParseIntError,
},
#[snafu(display("Found invalid character in octet string"))]
InvalidJerOctetString {},
#[snafu(display("Failed to construct OID from value {value}",))]
InvalidOIDString {
value: serde_json::Value,
},
#[snafu(display("Found invalid enumerated discriminant {discriminant}",))]
InvalidEnumDiscriminant {
discriminant: alloc::string::String,
},
}
impl JerDecodeErrorKind {
#[must_use]
pub fn eoi() -> CodecDecodeError {
CodecDecodeError::Jer(JerDecodeErrorKind::EndOfInput {})
}
}
#[derive(Snafu, Debug)]
#[snafu(visibility(pub))]
#[non_exhaustive]
pub enum UperDecodeErrorKind {}
#[derive(Snafu, Debug)]
#[snafu(visibility(pub))]
#[non_exhaustive]
pub enum AperDecodeErrorKind {}
#[derive(Snafu, Debug)]
#[snafu(visibility(pub))]
#[non_exhaustive]
pub enum XerDecodeErrorKind {
#[snafu(display("Unexpected end of input while decoding XER"))]
EndOfXmlInput {},
#[snafu(display(
"Found mismatching XML value. Expected type: {}. Found value: {}.",
needed,
found
))]
XmlTypeMismatch {
needed: &'static str,
found: alloc::string::String,
},
#[snafu(display("Found invalid character in octet string"))]
InvalidXerOctetstring {
parse_int_err: ParseIntError,
},
#[snafu(display("Encountered invalid value: {details}"))]
InvalidInput {
details: &'static str,
},
#[snafu(display("Found invalid open type encoding: {inner_err}"))]
InvalidOpenType {
inner_err: xml_no_std::writer::Error,
},
#[snafu(display("XML parser error: {details}"))]
XmlParser {
details: alloc::string::String,
},
#[snafu(display("Error matching tag names: expected {needed}, found {found}"))]
XmlTag {
needed: alloc::string::String,
found: alloc::string::String,
},
#[snafu(display("Encoding violates ITU-T X.693 (02/2021): {details}"))]
SpecViolation {
details: alloc::string::String,
},
}
#[derive(Snafu, Debug)]
#[snafu(visibility(pub))]
#[non_exhaustive]
pub enum OerDecodeErrorKind {
#[snafu(display("Invalid tag class when decoding choice: actual {:?}", class))]
InvalidTagClassOnChoice {
class: u8,
},
#[snafu(display("Invalid tag number when decoding Choice: {value}"))]
InvalidTagNumberOnChoice {
value: u32,
},
#[snafu(display(
"Tag not found from the variants of the platform when decoding Choice. Tag: {value}, extensible status: {is_extensible}"
))]
InvalidTagVariantOnChoice {
value: Tag,
is_extensible: bool,
},
InvalidExtensionHeader {
msg: alloc::string::String,
},
#[snafu(display("Invalid BitString: {msg}"))]
InvalidOerBitString {
msg: alloc::string::String,
},
#[snafu(display("Invalid preamble: {msg}"))]
InvalidPreamble {
msg: alloc::string::String,
},
}
impl OerDecodeErrorKind {
#[must_use]
pub fn invalid_tag_number_on_choice(value: u32) -> DecodeError {
CodecDecodeError::Oer(Self::InvalidTagNumberOnChoice { value }).into()
}
#[must_use]
pub fn invalid_tag_variant_on_choice(value: Tag, is_extensible: bool) -> DecodeError {
CodecDecodeError::Oer(Self::InvalidTagVariantOnChoice {
value,
is_extensible,
})
.into()
}
#[must_use]
pub fn invalid_extension_header(msg: alloc::string::String) -> DecodeError {
CodecDecodeError::Oer(Self::InvalidExtensionHeader { msg }).into()
}
#[must_use]
pub fn invalid_bit_string(msg: alloc::string::String) -> DecodeError {
CodecDecodeError::Oer(Self::InvalidOerBitString { msg }).into()
}
#[must_use]
pub fn invalid_preamble(msg: alloc::string::String) -> DecodeError {
CodecDecodeError::Oer(Self::InvalidPreamble { msg }).into()
}
}
#[derive(Snafu, Debug)]
#[snafu(visibility(pub))]
#[non_exhaustive]
pub enum CoerDecodeErrorKind {
#[snafu(display(
"Invalid Canonical Octet Encoding, not encoded as the smallest possible number of octets: {msg}"
))]
NotValidCanonicalEncoding {
msg: alloc::string::String,
},
}
impl crate::de::Error for DecodeError {
fn custom<D: core::fmt::Display>(msg: D, codec: Codec) -> Self {
Self::from_kind(
DecodeErrorKind::Custom {
msg: msg.to_string(),
},
codec,
)
}
fn incomplete(needed: nom::Needed, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::Incomplete { needed }, codec)
}
fn exceeds_max_length(length: num_bigint::BigUint, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::ExceedsMaxLength { length }, codec)
}
fn missing_field(name: &'static str, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::MissingField { name }, codec)
}
fn no_valid_choice(name: &'static str, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::NoValidChoice { name }, codec)
}
fn field_error(name: &'static str, nested: DecodeError, codec: Codec) -> Self {
Self::from_kind(
DecodeErrorKind::FieldError {
name,
nested: Box::new(nested),
},
codec,
)
}
fn duplicate_field(name: &'static str, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::DuplicateField { name }, codec)
}
fn unknown_field(index: usize, tag: Tag, codec: Codec) -> Self {
Self::from_kind(DecodeErrorKind::UnknownField { index, tag }, codec)
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
fn test_ber_decode_date() {
use crate::error::{DecodeError, DecodeErrorKind};
let data = [
23, 17, 50, 51, 48, 49, 50, 50, 49, 51, 48, 48, 48, 48, 45, 48, 53, 48, 90,
];
let result = crate::ber::decode::<UtcTime>(&data);
match result {
Err(DecodeError { kind, .. }) => {
if let DecodeErrorKind::CodecSpecific {
inner:
crate::error::CodecDecodeError::Ber(
crate::error::BerDecodeErrorKind::InvalidDate { msg },
),
..
} = *kind
{
assert_eq!(msg, "230122130000-050Z");
} else {
panic!("Unexpected error kind: {kind}");
}
}
Ok(_) => panic!("Expected error"),
}
}
#[test]
fn test_uper_missing_choice_index() {
use crate as rasn;
use crate::Codec;
use crate::error::{DecodeError, DecodeErrorKind};
#[derive(AsnType, Decode, Debug, PartialEq)]
#[rasn(choice, automatic_tags)]
enum MyChoice {
Normal(Integer),
High(Integer),
Medium(Integer),
}
let data = [192, 128, 83, 64];
let result = Codec::Uper.decode_from_binary::<MyChoice>(&data);
match result {
Ok(_) => {
panic!("Unexpected OK!");
}
Err(DecodeError { kind, .. }) => {
if let DecodeErrorKind::ChoiceIndexNotFound { index, .. } = *kind {
assert_eq!(index, 3);
} else {
panic!("Unexpected error kind: {kind}");
}
}
}
}
}