11//! Context-specific field.
22
33use crate :: {
4- Choice , Decode , DecodeValue , DerOrd , Encode , EncodeValue , EncodeValueRef , Error , Header ,
4+ Choice , Class , Decode , DecodeValue , DerOrd , Encode , EncodeValue , EncodeValueRef , Error , Header ,
55 Length , Reader , Tag , TagMode , TagNumber , Tagged , ValueOrd , Writer , asn1:: AnyRef ,
66} ;
77use core:: cmp:: Ordering ;
@@ -46,7 +46,9 @@ impl<T> ContextSpecific<T> {
4646 where
4747 T : Decode < ' a > ,
4848 {
49- Self :: decode_with ( reader, tag_number, |reader| Self :: decode ( reader) )
49+ peek_decode_optional ( reader, Class :: ContextSpecific , tag_number, |reader| {
50+ Self :: decode ( reader)
51+ } )
5052 }
5153
5254 /// Attempt to decode an `IMPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the
@@ -62,45 +64,50 @@ impl<T> ContextSpecific<T> {
6264 where
6365 T : DecodeValue < ' a > + Tagged ,
6466 {
65- Self :: decode_with :: < _ , _ , T :: Error > ( reader, tag_number, |reader| {
66- let header = Header :: decode ( reader) ?;
67- let value = T :: decode_value ( reader, header) ?;
68-
69- if header. tag . is_constructed ( ) != value. tag ( ) . is_constructed ( ) {
70- return Err ( header. tag . non_canonical_error ( ) . into ( ) ) ;
71- }
72-
73- Ok ( Self {
74- tag_number,
75- tag_mode : TagMode :: Implicit ,
76- value,
77- } )
78- } )
67+ peek_decode_optional :: < Self , _ , _ , T :: Error > (
68+ reader,
69+ Class :: ContextSpecific ,
70+ tag_number,
71+ |reader| {
72+ let header = Header :: decode ( reader) ?;
73+ let value = T :: decode_value ( reader, header) ?;
74+
75+ if header. tag . is_constructed ( ) != value. tag ( ) . is_constructed ( ) {
76+ return Err ( header. tag . non_canonical_error ( ) . into ( ) ) ;
77+ }
78+
79+ Ok ( Self {
80+ tag_number,
81+ tag_mode : TagMode :: Implicit ,
82+ value,
83+ } )
84+ } ,
85+ )
7986 }
87+ }
8088
81- /// Attempt to decode a context-specific field with the given
82- /// helper callback.
83- fn decode_with < ' a , F , R : Reader < ' a > , E > (
84- reader : & mut R ,
85- tag_number : TagNumber ,
86- f : F ,
87- ) -> Result < Option < Self > , E >
88- where
89- F : FnOnce ( & mut R ) -> Result < Self , E > ,
90- E : From < Error > ,
91- {
92- while let Some ( tag) = Tag :: peek_optional ( reader) ? {
93- if !tag. is_context_specific ( ) || ( tag. number ( ) > tag_number) {
94- break ;
95- } else if tag. number ( ) == tag_number {
96- return Some ( f ( reader) ) . transpose ( ) ;
97- } else {
98- AnyRef :: decode ( reader) ?;
99- }
100- }
101-
102- Ok ( None )
89+ /// Attempt to decode a context-specific (or any given class) field
90+ /// with the given helper callback.
91+ fn peek_decode_optional < ' a , T , F , R : Reader < ' a > , E > (
92+ reader : & mut R ,
93+ class : Class ,
94+ tag_number : TagNumber ,
95+ f : F ,
96+ ) -> Result < Option < T > , E >
97+ where
98+ F : FnOnce ( & mut R ) -> Result < T , E > ,
99+ E : From < Error > ,
100+ {
101+ // Peek tag or ignore end of stream
102+ let Some ( tag) = Tag :: peek_optional ( reader) ? else {
103+ return Ok ( None ) ;
104+ } ;
105+ // Ignore tags with different numbers
106+ if tag. class ( ) != class || tag. number ( ) != tag_number {
107+ return Ok ( None ) ;
103108 }
109+ // Tag matches - callback reads tag and decodes value
110+ Some ( f ( reader) ) . transpose ( )
104111}
105112
106113impl < ' a , T > Choice < ' a > for ContextSpecific < T >
@@ -335,13 +342,11 @@ mod tests {
335342 }
336343
337344 #[ test]
338- fn context_specific_skipping_unknown_field ( ) {
345+ fn context_specific_not_skipping_unknown_field ( ) {
339346 let tag = TagNumber ( 1 ) ;
340347 let mut reader = SliceReader :: new ( & hex ! ( "A003020100A103020101" ) ) . unwrap ( ) ;
341- let field = ContextSpecific :: < u8 > :: decode_explicit ( & mut reader, tag)
342- . unwrap ( )
343- . unwrap ( ) ;
344- assert_eq ! ( field. value, 1 ) ;
348+ let field = ContextSpecific :: < u8 > :: decode_explicit ( & mut reader, tag) . unwrap ( ) ;
349+ assert_eq ! ( field, None ) ;
345350 }
346351
347352 #[ test]
0 commit comments