@@ -7,258 +7,21 @@ use crate::{
7
7
} ;
8
8
use core:: cmp:: Ordering ;
9
9
10
- /// Context-specific field which wraps an owned inner value.
11
- ///
12
- /// This type decodes/encodes a field which is specific to a particular context
13
- /// and is identified by a [`TagNumber`].
14
- #[ derive( Copy , Clone , Debug , Eq , PartialEq , PartialOrd , Ord ) ]
15
- pub struct ContextSpecific < T > {
16
- /// Context-specific tag number sans the leading `0b10000000` class
17
- /// identifier bit and `0b100000` constructed flag.
18
- pub tag_number : TagNumber ,
19
-
20
- /// Tag mode: `EXPLICIT` VS `IMPLICIT`.
21
- pub tag_mode : TagMode ,
22
-
23
- /// Value of the field.
24
- pub value : T ,
25
- }
26
-
27
- impl < T > ContextSpecific < T > {
28
- /// Attempt to decode an `EXPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the
29
- /// provided [`TagNumber`].
30
- ///
31
- /// This method has the following behavior which decodes tag numbers one by one
32
- /// in extension fields, which are denoted in an ASN.1 schema using
33
- /// the `...` ellipsis extension marker:
34
- ///
35
- /// - Returns `Ok(None)` if anything other than a [`ContextSpecific`] field
36
- /// is encountered.
37
- /// - Returns `Ok(None)` if a [`ContextSpecific`] field with a different tag
38
- /// number is encountered. These fields are not consumed in this case.
39
- /// - Returns `Err(ErrorKind::Noncanonical)` if constructed bit is primitive.
40
- /// - Returns `Ok(Some(..))` if tag number matches.
41
- pub fn decode_explicit < ' a , R : Reader < ' a > > (
42
- reader : & mut R ,
43
- tag_number : TagNumber ,
44
- ) -> Result < Option < Self > , T :: Error >
45
- where
46
- T : Decode < ' a > ,
47
- {
48
- if !Tag :: peek_matches ( reader, Class :: ContextSpecific , tag_number) ? {
49
- return Ok ( None ) ;
50
- }
51
- Ok ( Some ( Self :: decode ( reader) ?) )
52
- }
53
-
54
- /// Attempt to decode an `IMPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the
55
- /// provided [`TagNumber`].
56
- ///
57
- /// This method otherwise behaves the same as `decode_explicit`,
58
- /// but should be used in cases where the particular fields are `IMPLICIT`
59
- /// as opposed to `EXPLICIT`.
60
- ///
61
- /// Differences from `EXPLICIT`:
62
- /// - Returns `Err(ErrorKind::Noncanonical)` if constructed bit
63
- /// does not match constructed bit of the base encoding.
64
- pub fn decode_implicit < ' a , R : Reader < ' a > > (
65
- reader : & mut R ,
66
- tag_number : TagNumber ,
67
- ) -> Result < Option < Self > , T :: Error >
68
- where
69
- T : DecodeValue < ' a > + IsConstructed ,
70
- {
71
- // Peek tag number
72
- if !Tag :: peek_matches ( reader, Class :: ContextSpecific , tag_number) ? {
73
- return Ok ( None ) ;
74
- }
75
- // Decode IMPLICIT header
76
- let header = Header :: decode ( reader) ?;
77
-
78
- // read_nested checks if header matches decoded length
79
- let value = reader. read_nested ( header. length , |reader| {
80
- // Decode inner IMPLICIT value
81
- T :: decode_value ( reader, header)
82
- } ) ?;
83
-
84
- // the encoding shall be constructed if the base encoding is constructed
85
- if header. tag . is_constructed ( ) != T :: CONSTRUCTED {
86
- return Err ( header. tag . non_canonical_error ( ) . into ( ) ) ;
87
- }
88
-
89
- Ok ( Some ( Self {
90
- tag_number,
91
- tag_mode : TagMode :: Implicit ,
92
- value,
93
- } ) )
94
- }
95
- }
96
-
97
- impl < ' a , T > Choice < ' a > for ContextSpecific < T >
98
- where
99
- T : Decode < ' a > + Tagged ,
100
- {
101
- fn can_decode ( tag : Tag ) -> bool {
102
- tag. is_context_specific ( )
103
- }
104
- }
105
-
106
- impl < ' a , T > Decode < ' a > for ContextSpecific < T >
107
- where
108
- T : Decode < ' a > ,
109
- {
110
- type Error = T :: Error ;
111
-
112
- fn decode < R : Reader < ' a > > ( reader : & mut R ) -> Result < Self , Self :: Error > {
113
- // Decode EXPLICIT header
114
- let header = Header :: decode ( reader) ?;
115
-
116
- // encoding shall be constructed
117
- if !header. tag . is_constructed ( ) {
118
- return Err ( header. tag . non_canonical_error ( ) . into ( ) ) ;
119
- }
120
- match header. tag {
121
- Tag :: ContextSpecific { number, .. } => Ok ( Self {
122
- tag_number : number,
123
- tag_mode : TagMode :: default ( ) ,
124
- value : reader. read_nested ( header. length , |reader| {
125
- // Decode inner tag-length-value of EXPLICIT
126
- T :: decode ( reader)
127
- } ) ?,
128
- } ) ,
129
- tag => Err ( tag. unexpected_error ( None ) . into ( ) ) ,
130
- }
131
- }
132
- }
133
-
134
- impl < T > EncodeValue for ContextSpecific < T >
135
- where
136
- T : EncodeValue + Tagged ,
137
- {
138
- fn value_len ( & self ) -> Result < Length , Error > {
139
- match self . tag_mode {
140
- TagMode :: Explicit => self . value . encoded_len ( ) ,
141
- TagMode :: Implicit => self . value . value_len ( ) ,
142
- }
143
- }
144
-
145
- fn encode_value ( & self , writer : & mut impl Writer ) -> Result < ( ) , Error > {
146
- match self . tag_mode {
147
- TagMode :: Explicit => self . value . encode ( writer) ,
148
- TagMode :: Implicit => self . value . encode_value ( writer) ,
149
- }
150
- }
151
- }
152
-
153
- impl < T > Tagged for ContextSpecific < T >
154
- where
155
- T : Tagged ,
156
- {
157
- fn tag ( & self ) -> Tag {
158
- let constructed = match self . tag_mode {
159
- // ISO/IEC 8825-1:2021
160
- // 8.14.3 If implicit tagging (see Rec. ITU-T X.680 | ISO/IEC 8824-1, 31.2.7) was not used in the definition of the type, the
161
- // encoding shall be constructed and the contents octets shall be the complete base encoding [Encode].
162
- TagMode :: Explicit => true ,
163
-
164
- // ISO/IEC 8825-1:2021
165
- // 8.14.4 If implicit tagging was used in the definition of the type, then:
166
- // a) the encoding shall be constructed if the base encoding is constructed, and shall be primitive otherwise; and
167
- // b) the contents octets shall be the same as the contents octets [EncodeValue] of the base encoding.
168
- //
169
- // TODO(dishmaker): use IsConstructed trait for IMPLICIT
170
- TagMode :: Implicit => self . value . tag ( ) . is_constructed ( ) ,
171
- } ;
172
-
173
- Tag :: ContextSpecific {
174
- number : self . tag_number ,
175
- constructed,
176
- }
177
- }
178
- }
179
-
180
- impl < ' a , T > TryFrom < AnyRef < ' a > > for ContextSpecific < T >
181
- where
182
- T : Decode < ' a > ,
183
- {
184
- type Error = T :: Error ;
185
-
186
- fn try_from ( any : AnyRef < ' a > ) -> Result < ContextSpecific < T > , Self :: Error > {
187
- match any. tag ( ) {
188
- Tag :: ContextSpecific {
189
- number,
190
- constructed : true ,
191
- } => Ok ( Self {
192
- tag_number : number,
193
- tag_mode : TagMode :: default ( ) ,
194
- value : T :: from_der ( any. value ( ) ) ?,
195
- } ) ,
196
- tag => Err ( tag. unexpected_error ( None ) . into ( ) ) ,
197
- }
198
- }
199
- }
200
-
201
- impl < T > ValueOrd for ContextSpecific < T >
202
- where
203
- T : EncodeValue + ValueOrd + Tagged ,
204
- {
205
- fn value_cmp ( & self , other : & Self ) -> Result < Ordering , Error > {
206
- match self . tag_mode {
207
- TagMode :: Explicit => self . der_cmp ( other) ,
208
- TagMode :: Implicit => self . value_cmp ( other) ,
209
- }
210
- }
211
- }
212
-
213
- /// Context-specific field reference.
214
- ///
215
- /// This type encodes a field which is specific to a particular context
216
- /// and is identified by a [`TagNumber`].
217
- #[ derive( Copy , Clone , Debug , Eq , PartialEq , PartialOrd , Ord ) ]
218
- pub struct ContextSpecificRef < ' a , T > {
219
- /// Context-specific tag number sans the leading `0b10000000` class
220
- /// identifier bit and `0b100000` constructed flag.
221
- pub tag_number : TagNumber ,
222
-
223
- /// Tag mode: `EXPLICIT` VS `IMPLICIT`.
224
- pub tag_mode : TagMode ,
225
-
226
- /// Value of the field.
227
- pub value : & ' a T ,
228
- }
229
-
230
- impl < ' a , T > ContextSpecificRef < ' a , T > {
231
- /// Convert to a [`ContextSpecific`].
232
- fn encoder ( & self ) -> ContextSpecific < EncodeValueRef < ' a , T > > {
233
- ContextSpecific {
234
- tag_number : self . tag_number ,
235
- tag_mode : self . tag_mode ,
236
- value : EncodeValueRef ( self . value ) ,
237
- }
238
- }
239
- }
240
-
241
- impl < T > EncodeValue for ContextSpecificRef < ' _ , T >
242
- where
243
- T : EncodeValue + Tagged ,
244
- {
245
- fn value_len ( & self ) -> Result < Length , Error > {
246
- self . encoder ( ) . value_len ( )
247
- }
248
-
249
- fn encode_value ( & self , writer : & mut impl Writer ) -> Result < ( ) , Error > {
250
- self . encoder ( ) . encode_value ( writer)
251
- }
252
- }
253
-
254
- impl < T > Tagged for ContextSpecificRef < ' _ , T >
255
- where
256
- T : Tagged ,
257
- {
258
- fn tag ( & self ) -> Tag {
259
- self . encoder ( ) . tag ( )
260
- }
261
- }
10
+ #[ cfg( doc) ]
11
+ use crate :: ErrorKind ;
12
+
13
+ impl_custom_class ! (
14
+ ContextSpecific ,
15
+ ContextSpecific ,
16
+ "CONTEXT-SPECIFIC" ,
17
+ "0b10000000"
18
+ ) ;
19
+ impl_custom_class_ref ! (
20
+ ContextSpecificRef ,
21
+ ContextSpecific ,
22
+ "CONTEXT-SPECIFIC" ,
23
+ "0b10000000"
24
+ ) ;
262
25
263
26
#[ cfg( test) ]
264
27
#[ allow( clippy:: unwrap_used) ]
0 commit comments