@@ -419,29 +419,52 @@ pub(crate) fn python_class_to_annotated<'p>(
419419 }
420420}
421421
422- pub ( crate ) fn type_to_tag ( t : & Type , encoding : & Option < pyo3:: Py < Encoding > > ) -> asn1:: Tag {
423- let inner_tag = match t {
424- Type :: Sequence ( _, _) => asn1:: Sequence :: TAG ,
425- Type :: SequenceOf ( _) => asn1:: Sequence :: TAG ,
426- Type :: Option ( t) => type_to_tag ( t. get ( ) . inner . get ( ) , encoding) ,
427- Type :: PyBool ( ) => bool:: TAG ,
428- Type :: PyInt ( ) => asn1:: BigInt :: TAG ,
429- Type :: PyBytes ( ) => <& [ u8 ] as SimpleAsn1Readable >:: TAG ,
430- Type :: PyStr ( ) => asn1:: Utf8String :: TAG ,
431- Type :: PrintableString ( ) => asn1:: PrintableString :: TAG ,
432- Type :: IA5String ( ) => asn1:: IA5String :: TAG ,
433- Type :: ObjectIdentifier ( ) => asn1:: ObjectIdentifier :: TAG ,
434- Type :: UtcTime ( ) => asn1:: UtcTime :: TAG ,
435- Type :: GeneralizedTime ( ) => asn1:: GeneralizedTime :: TAG ,
436- Type :: BitString ( ) => asn1:: BitString :: TAG ,
437- } ;
438-
439- match encoding {
422+ // Checks if encoding `tag_without_encoding` using `encoding` results
423+ // in `tag`
424+ fn check_tag_with_encoding (
425+ tag_without_encoding : asn1:: Tag ,
426+ encoding : & Option < pyo3:: Py < Encoding > > ,
427+ tag : asn1:: Tag ,
428+ ) -> bool {
429+ let tag_with_encoding = match encoding {
440430 Some ( e) => match e. get ( ) {
441- Encoding :: Implicit ( n) => asn1:: implicit_tag ( * n, inner_tag ) ,
431+ Encoding :: Implicit ( n) => asn1:: implicit_tag ( * n, tag_without_encoding ) ,
442432 Encoding :: Explicit ( n) => asn1:: explicit_tag ( * n) ,
443433 } ,
444- None => inner_tag,
434+ None => tag_without_encoding,
435+ } ;
436+ tag_with_encoding == tag
437+ }
438+
439+ // Given `tag` and `encoding`, returns whether that tag with that encoding
440+ // matches what one would expect to see when decoding `type_`
441+ pub ( crate ) fn is_tag_valid_for_type (
442+ tag : asn1:: Tag ,
443+ type_ : & Type ,
444+ encoding : & Option < pyo3:: Py < Encoding > > ,
445+ ) -> bool {
446+ match type_ {
447+ Type :: Sequence ( _, _) => check_tag_with_encoding ( asn1:: Sequence :: TAG , encoding, tag) ,
448+ Type :: SequenceOf ( _) => check_tag_with_encoding ( asn1:: Sequence :: TAG , encoding, tag) ,
449+ Type :: Option ( t) => is_tag_valid_for_type ( tag, t. get ( ) . inner . get ( ) , encoding) ,
450+ Type :: PyBool ( ) => check_tag_with_encoding ( bool:: TAG , encoding, tag) ,
451+ Type :: PyInt ( ) => check_tag_with_encoding ( asn1:: BigInt :: TAG , encoding, tag) ,
452+ Type :: PyBytes ( ) => {
453+ check_tag_with_encoding ( <& [ u8 ] as SimpleAsn1Readable >:: TAG , encoding, tag)
454+ }
455+ Type :: PyStr ( ) => check_tag_with_encoding ( asn1:: Utf8String :: TAG , encoding, tag) ,
456+ Type :: PrintableString ( ) => {
457+ check_tag_with_encoding ( asn1:: PrintableString :: TAG , encoding, tag)
458+ }
459+ Type :: IA5String ( ) => check_tag_with_encoding ( asn1:: IA5String :: TAG , encoding, tag) ,
460+ Type :: ObjectIdentifier ( ) => {
461+ check_tag_with_encoding ( asn1:: ObjectIdentifier :: TAG , encoding, tag)
462+ }
463+ Type :: UtcTime ( ) => check_tag_with_encoding ( asn1:: UtcTime :: TAG , encoding, tag) ,
464+ Type :: GeneralizedTime ( ) => {
465+ check_tag_with_encoding ( asn1:: GeneralizedTime :: TAG , encoding, tag)
466+ }
467+ Type :: BitString ( ) => check_tag_with_encoding ( asn1:: BitString :: TAG , encoding, tag) ,
445468 }
446469}
447470
@@ -468,14 +491,15 @@ pub(crate) fn check_size_constraint(
468491#[ cfg( test) ]
469492mod tests {
470493
494+ use asn1:: SimpleAsn1Readable ;
471495 use pyo3:: IntoPyObject ;
472496
473- use super :: { type_to_tag , AnnotatedType , Annotation , Type } ;
497+ use super :: { is_tag_valid_for_type , AnnotatedType , Annotation , Type } ;
474498
475499 #[ test]
476- // Needed for coverage of `type_to_tag (Type::Option(..))`, since
477- // `type_to_tag ` is never called with an optional value.
478- fn test_option_type_to_tag ( ) {
500+ // Needed for coverage of `is_tag_valid_for_type (Type::Option(..))`, since
501+ // `is_tag_valid_for_type ` is never called with an optional value.
502+ fn test_option_is_tag_valid_for_type ( ) {
479503 pyo3:: Python :: initialize ( ) ;
480504
481505 pyo3:: Python :: attach ( |py| {
@@ -509,8 +533,11 @@ mod tests {
509533 } ,
510534 )
511535 . unwrap ( ) ;
512- let expected_tag = type_to_tag ( & Type :: Option ( optional_type) , & None ) ;
513- assert_eq ! ( expected_tag, type_to_tag( & Type :: PyInt ( ) , & None ) )
536+ assert ! ( is_tag_valid_for_type(
537+ asn1:: BigInt :: TAG ,
538+ & Type :: Option ( optional_type) ,
539+ & None
540+ ) ) ;
514541 } )
515542 }
516543}
0 commit comments