1use crate::{
4 Choice, Class, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, Error, Header,
5 Length, Reader, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, asn1::AnyRef,
6 tag::IsConstructed,
7};
8use core::cmp::Ordering;
9
10#[cfg(doc)]
11use crate::ErrorKind;
12
13impl_custom_class!(
14 ContextSpecific,
15 ContextSpecific,
16 "CONTEXT-SPECIFIC",
17 "0b10000000"
18);
19impl_custom_class_ref!(
20 ContextSpecificRef,
21 ContextSpecific,
22 "CONTEXT-SPECIFIC",
23 "0b10000000"
24);
25
26#[cfg(test)]
27#[allow(clippy::unwrap_used)]
28mod tests {
29 use super::ContextSpecific;
30 use crate::{Decode, Encode, SliceReader, TagMode, TagNumber, asn1::BitStringRef};
31 use hex_literal::hex;
32
33 #[cfg(feature = "heapless")]
34 use crate::asn1::{ContextSpecificRef, SetOf, Utf8StringRef};
35
36 #[test]
37 fn value_ord() {
38 use crate::{DerOrd, ValueOrd};
39 use core::cmp::Ordering;
40
41 for tag_mode in [TagMode::Explicit, TagMode::Implicit] {
42 let field = |value: u8| ContextSpecific {
43 tag_number: TagNumber(1),
44 tag_mode,
45 value,
46 };
47 assert_eq!(field(5).value_cmp(&field(6)), Ok(Ordering::Less));
48 assert_eq!(field(6).der_cmp(&field(5)), Ok(Ordering::Greater));
49 assert_eq!(field(5).der_cmp(&field(5)), Ok(Ordering::Equal));
50 }
51 }
52
53 const EXAMPLE_BYTES: &[u8] =
55 &hex!("A123032100A3A7EAE3A8373830BC47E1167BC50E1DB551999651E0E2DC587623438EAC3F31");
56
57 #[test]
58 fn round_trip() {
59 let field = ContextSpecific::<BitStringRef<'_>>::from_der(EXAMPLE_BYTES).unwrap();
60 assert_eq!(field.tag_number.value(), 1);
61 assert_eq!(
62 field.value,
63 BitStringRef::from_bytes(&EXAMPLE_BYTES[5..]).unwrap()
64 );
65
66 let mut buf = [0u8; 128];
67 let encoded = field.encode_to_slice(&mut buf).unwrap();
68 assert_eq!(encoded, EXAMPLE_BYTES);
69 }
70
71 #[test]
72 fn context_specific_with_explicit_field() {
73 let tag_number = TagNumber(0);
74
75 let mut reader = SliceReader::new(&[]).unwrap();
77 assert_eq!(
78 ContextSpecific::<u8>::decode_explicit(&mut reader, tag_number).unwrap(),
79 None
80 );
81
82 let mut reader = SliceReader::new(&hex!("020100")).unwrap();
84 assert_eq!(
85 ContextSpecific::<u8>::decode_explicit(&mut reader, tag_number).unwrap(),
86 None
87 );
88
89 let mut reader = SliceReader::new(&hex!("A003020100")).unwrap();
91 let field = ContextSpecific::<u8>::decode_explicit(&mut reader, tag_number)
92 .unwrap()
93 .unwrap();
94
95 assert_eq!(field.tag_number, tag_number);
96 assert_eq!(field.tag_mode, TagMode::Explicit);
97 assert_eq!(field.value, 0);
98 }
99
100 #[test]
101 fn context_specific_with_implicit_field() {
102 let context_specific_implicit_bytes =
109 hex!("81210019BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6CB0C5C38AD703166E1");
110
111 let tag_number = TagNumber(1);
112
113 let mut reader = SliceReader::new(&context_specific_implicit_bytes).unwrap();
114 let field = ContextSpecific::<BitStringRef<'_>>::decode_implicit(&mut reader, tag_number)
115 .unwrap()
116 .unwrap();
117
118 assert_eq!(field.tag_number, tag_number);
119 assert_eq!(field.tag_mode, TagMode::Implicit);
120 assert_eq!(
121 field.value.as_bytes().unwrap(),
122 &context_specific_implicit_bytes[3..]
123 );
124 }
125
126 #[test]
127 fn context_specific_not_skipping_unknown_field() {
128 let tag = TagNumber(1);
129 let mut reader = SliceReader::new(&hex!("A003020100A103020101")).unwrap();
130 let field = ContextSpecific::<u8>::decode_explicit(&mut reader, tag).unwrap();
131 assert_eq!(field, None);
132 }
133
134 #[test]
135 fn context_specific_returns_none_on_greater_tag_number() {
136 let tag = TagNumber(0);
137 let mut reader = SliceReader::new(&hex!("A103020101")).unwrap();
138 assert_eq!(
139 ContextSpecific::<u8>::decode_explicit(&mut reader, tag).unwrap(),
140 None
141 );
142 }
143
144 #[test]
145 #[cfg(feature = "heapless")]
146 fn context_specific_explicit_ref() {
147 let mut set = SetOf::new();
148 set.insert(8u16).unwrap();
149 set.insert(7u16).unwrap();
150
151 let field = ContextSpecificRef::<SetOf<u16, 2>> {
152 value: &set,
153 tag_number: TagNumber(2),
154 tag_mode: TagMode::Explicit,
155 };
156
157 let mut buf = [0u8; 16];
158 let encoded = field.encode_to_slice(&mut buf).unwrap();
159 assert_eq!(
160 encoded,
161 &[
162 0xA2, 0x08, 0x31, 0x06,
163 0x02, 0x01, 0x07, 0x02, 0x01, 0x08
164 ]
165 );
166
167 let mut reader = SliceReader::new(encoded).unwrap();
168 let field = ContextSpecific::<SetOf<u16, 2>>::decode_explicit(&mut reader, TagNumber(2))
169 .unwrap()
170 .unwrap();
171
172 assert_eq!(field.value.len(), 2);
173 assert_eq!(field.value.get(0).cloned(), Some(7));
174 assert_eq!(field.value.get(1).cloned(), Some(8));
175 }
176
177 #[test]
178 #[cfg(feature = "heapless")]
179 fn context_specific_implicit_ref() {
180 let hello = Utf8StringRef::new("Hello").unwrap();
181 let world = Utf8StringRef::new("world").unwrap();
182
183 let mut set = SetOf::new();
184 set.insert(hello).unwrap();
185 set.insert(world).unwrap();
186
187 let field = ContextSpecificRef::<SetOf<Utf8StringRef<'_>, 2>> {
188 value: &set,
189 tag_number: TagNumber(2),
190 tag_mode: TagMode::Implicit,
191 };
192
193 let mut buf = [0u8; 16];
194 let encoded = field.encode_to_slice(&mut buf).unwrap();
195 assert_eq!(
196 encoded,
197 &[
198 0xA2, 0x0E, 0x0C, 0x05, b'H', b'e', b'l', b'l', b'o', 0x0C, 0x05, b'w', b'o', b'r', b'l', b'd', ]
202 );
203
204 let mut reader = SliceReader::new(encoded).unwrap();
205 let field = ContextSpecific::<SetOf<Utf8StringRef<'_>, 2>>::decode_implicit(
206 &mut reader,
207 TagNumber(2),
208 )
209 .unwrap()
210 .unwrap();
211
212 assert_eq!(field.value.len(), 2);
213 assert_eq!(field.value.get(0).cloned(), Some(hello));
214 assert_eq!(field.value.get(1).cloned(), Some(world));
215 }
216}