1#![allow(path_statements)]
2
3use alloc::{string::String, string::ToString, vec::Vec};
4
5use crate::{
6 decode::{COctetStringDecodeError, Decode, DecodeError},
7 encode::{Encode, Length},
8};
9
10#[derive(Debug)]
12pub enum Error {
13 TooManyBytes { actual: usize, max: usize },
14 TooFewBytes { actual: usize },
15 NotNullTerminated,
16 NotAscii,
17 NullByteFound,
18}
19
20impl core::fmt::Display for Error {
21 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
22 match self {
23 Self::TooManyBytes { actual, max } => {
24 write!(f, "Too many bytes. actual: {actual}, max: {max}")
25 }
26 Self::TooFewBytes { actual } => {
27 write!(f, "Too few bytes. actual: {actual}, min: 1")
28 }
29 Self::NotNullTerminated => write!(f, "Not null terminated"),
30 Self::NotAscii => write!(f, "Not ASCII"),
31 Self::NullByteFound => write!(f, "Null byte found"),
32 }
33 }
34}
35
36impl core::error::Error for Error {}
37
38#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
56#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
57pub struct EmptyOrFullCOctetString<const N: usize> {
58 bytes: Vec<u8>,
59}
60
61impl<const N: usize> EmptyOrFullCOctetString<N> {
62 const _ASSERT_NON_ZERO: () = assert!(N > 0, "N must be greater than 0");
63
64 #[inline]
68 pub fn null() -> Self {
69 Self::empty()
70 }
71
72 #[inline]
74 pub fn empty() -> Self {
75 Self::_ASSERT_NON_ZERO;
76
77 Self {
78 bytes: alloc::vec![0],
79 }
80 }
81
82 #[inline]
87 pub fn is_empty(&self) -> bool {
88 self.bytes.len() == 1
89 }
90
91 pub fn new(bytes: impl AsRef<[u8]>) -> Result<Self, Error> {
93 Self::_ASSERT_NON_ZERO;
94
95 let bytes = bytes.as_ref();
96
97 if bytes.is_empty() {
99 return Err(Error::TooFewBytes { actual: 0 });
100 }
101
102 if bytes.len() == 1 {
104 if bytes[0] != 0 {
105 return Err(Error::NotNullTerminated);
106 }
107
108 return Ok(Self {
109 bytes: bytes.to_vec(),
110 });
111 }
112
113 if bytes.len() < N {
114 return Err(Error::TooFewBytes {
115 actual: bytes.len(),
116 });
117 }
118
119 if bytes.len() > N {
120 return Err(Error::TooManyBytes {
121 actual: bytes.len(),
122 max: N,
123 });
124 }
125
126 if bytes[bytes.len() - 1] != 0 {
127 return Err(Error::NotNullTerminated);
128 }
129
130 if bytes[..bytes.len() - 1].contains(&0) {
131 return Err(Error::NullByteFound);
132 }
133
134 if !bytes.is_ascii() {
135 return Err(Error::NotAscii);
136 }
137
138 let bytes = bytes.to_vec();
139
140 Ok(Self { bytes })
141 }
142
143 #[inline]
145 pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
146 core::str::from_utf8(&self.bytes)
147 }
148
149 #[inline]
151 pub fn bytes(&self) -> &[u8] {
152 &self.bytes
153 }
154
155 #[inline]
157 pub fn into_bytes(self) -> Vec<u8> {
158 self.bytes
159 }
160}
161
162impl<const N: usize> core::fmt::Debug for EmptyOrFullCOctetString<N> {
163 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
164 f.debug_struct("EmptyOrFullCOctetString")
165 .field("bytes", &crate::utils::HexFormatter(&self.bytes))
166 .field("string", &self.to_string())
167 .finish()
168 }
169}
170
171impl<const N: usize> Default for EmptyOrFullCOctetString<N> {
172 fn default() -> Self {
173 Self::empty()
174 }
175}
176
177impl<const N: usize> core::str::FromStr for EmptyOrFullCOctetString<N> {
178 type Err = Error;
179
180 fn from_str(s: &str) -> Result<Self, Self::Err> {
182 Self::_ASSERT_NON_ZERO;
183
184 let bytes = s.as_bytes();
185
186 if bytes.len() + 1 > 1 {
188 if bytes.len() + 1 < N {
189 return Err(Error::TooFewBytes {
190 actual: bytes.len() + 1,
191 });
192 }
193
194 if bytes.len() + 1 > N {
195 return Err(Error::TooManyBytes {
196 actual: bytes.len() + 1,
197 max: N,
198 });
199 }
200 }
201
202 if !bytes.is_ascii() {
203 return Err(Error::NotAscii);
204 }
205
206 if bytes[..bytes.len()].contains(&0) {
207 return Err(Error::NullByteFound);
208 }
209
210 let mut bytes = bytes.to_vec();
211
212 bytes.push(0);
213
214 Ok(Self { bytes })
215 }
216}
217
218impl<const N: usize> core::fmt::Display for EmptyOrFullCOctetString<N> {
219 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
221 f.write_str(&String::from_utf8_lossy(&self.bytes))
222 }
223}
224
225impl<const N: usize> AsRef<[u8]> for EmptyOrFullCOctetString<N> {
226 fn as_ref(&self) -> &[u8] {
227 &self.bytes
228 }
229}
230
231impl<const N: usize> Length for EmptyOrFullCOctetString<N> {
232 fn length(&self) -> usize {
233 self.bytes.len()
234 }
235}
236
237impl<const N: usize> Encode for EmptyOrFullCOctetString<N> {
238 fn encode(&self, dst: &mut [u8]) -> usize {
239 _ = &mut dst[..self.bytes.len()].copy_from_slice(&self.bytes);
240
241 self.bytes.len()
242 }
243}
244
245impl<const N: usize> Decode for EmptyOrFullCOctetString<N> {
246 fn decode(src: &[u8]) -> Result<(Self, usize), DecodeError> {
247 Self::_ASSERT_NON_ZERO;
248
249 let mut bytes = Vec::with_capacity(N);
250
251 for i in 0..N {
252 if i >= src.len() {
253 return Err(DecodeError::unexpected_eof());
254 }
255
256 let byte = src[i];
257
258 bytes.push(byte);
259
260 if byte == 0 {
261 let len = i + 1;
262
263 if bytes.len() > 1 && bytes.len() < N {
264 return Err(DecodeError::c_octet_string_decode_error(
265 COctetStringDecodeError::TooFewBytes {
266 actual: bytes.len(),
267 min: N,
268 },
269 ));
270 }
271
272 if !bytes.is_ascii() {
273 return Err(DecodeError::c_octet_string_decode_error(
274 COctetStringDecodeError::NotAscii,
275 ));
276 }
277
278 return Ok((Self { bytes }, len));
279 }
280 }
281
282 Err(DecodeError::c_octet_string_decode_error(
283 COctetStringDecodeError::NotNullTerminated,
284 ))
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use super::*;
291
292 impl<const N: usize> crate::tests::TestInstance for EmptyOrFullCOctetString<N> {
293 fn instances() -> Vec<Self> {
294 alloc::vec![
295 Self::empty(),
296 Self::new(
297 core::iter::repeat_n(b'1', N - 1)
298 .chain(core::iter::once(b'\0'))
299 .collect::<Vec<_>>(),
300 )
301 .unwrap(),
302 ]
303 }
304 }
305
306 #[test]
307 fn encode_decode() {
308 crate::tests::encode_decode_test_instances::<EmptyOrFullCOctetString<1>>();
309 crate::tests::encode_decode_test_instances::<EmptyOrFullCOctetString<2>>();
310 crate::tests::encode_decode_test_instances::<EmptyOrFullCOctetString<3>>();
311 }
312
313 mod new {
314 use super::*;
315
316 #[test]
317 fn empty_too_few_bytes() {
318 let bytes = b"";
319 let error = EmptyOrFullCOctetString::<5>::new(bytes).unwrap_err();
320 assert!(matches!(error, Error::TooFewBytes { actual: 0 }));
321 }
322
323 #[test]
324 fn too_many_bytes() {
325 let bytes = b"Hello\0";
326 let error = EmptyOrFullCOctetString::<5>::new(bytes).unwrap_err();
327 assert!(matches!(error, Error::TooManyBytes { actual: 6, max: 5 }));
328 }
329
330 #[test]
331 fn too_few_bytes() {
332 let bytes = b"Hel\0";
333 let error = EmptyOrFullCOctetString::<5>::new(bytes).unwrap_err();
334 assert!(matches!(error, Error::TooFewBytes { actual: 4 }));
335 }
336
337 #[test]
338 fn not_null_terminated() {
339 let bytes = b"Hello";
340 let error = EmptyOrFullCOctetString::<5>::new(bytes).unwrap_err();
341 assert!(matches!(error, Error::NotNullTerminated));
342 }
343
344 #[test]
345 fn not_ascii() {
346 let bytes = b"Hell\xF0\0";
347 let error = EmptyOrFullCOctetString::<6>::new(bytes).unwrap_err();
348 assert!(matches!(error, Error::NotAscii));
349 }
350
351 #[test]
352 fn null_byte_found() {
353 let bytes = b"Hel\0lo\0";
354 let error = EmptyOrFullCOctetString::<7>::new(bytes).unwrap_err();
355 assert!(matches!(error, Error::NullByteFound));
356 }
357
358 #[test]
359 fn ok() {
360 let bytes = b"Hello\0";
361 let string = EmptyOrFullCOctetString::<6>::new(bytes).unwrap();
362 assert_eq!(string.bytes, bytes);
363 }
364
365 #[test]
366 fn ok_len() {
367 let bytes = b"Hello\0";
368 let string = EmptyOrFullCOctetString::<6>::new(bytes).unwrap();
369 assert_eq!(string.bytes.len(), 6);
370 assert_eq!(string.length(), 6);
371 }
372
373 #[test]
374 fn ok_empty() {
375 let bytes = b"\0";
376 let string = EmptyOrFullCOctetString::<6>::new(bytes).unwrap();
377 assert_eq!(string.bytes, bytes);
378 assert_eq!(string.bytes.len(), 1);
379 assert_eq!(string.length(), 1);
380 }
381 }
382
383 mod from_str {
384 use core::str::FromStr;
385
386 use super::*;
387
388 #[test]
389 fn too_many_bytes() {
390 let string = "Hello";
391 let error = EmptyOrFullCOctetString::<5>::from_str(string).unwrap_err();
392 assert!(matches!(error, Error::TooManyBytes { actual: 6, .. }));
393 }
394
395 #[test]
396 fn too_few_bytes() {
397 let string = "Hel";
398 let error = EmptyOrFullCOctetString::<5>::from_str(string).unwrap_err();
399 assert!(matches!(error, Error::TooFewBytes { actual: 4 }));
400 }
401
402 #[test]
403 fn null_byte_found() {
404 let string = "Hel\0lo";
405 let error = EmptyOrFullCOctetString::<7>::from_str(string).unwrap_err();
406 assert!(matches!(error, Error::NullByteFound));
407 }
408
409 #[test]
410 fn not_ascii() {
411 let string = "Hellö"; let error = EmptyOrFullCOctetString::<7>::from_str(string).unwrap_err();
413 assert!(matches!(error, Error::NotAscii));
414 }
415
416 #[test]
417 fn ok() {
418 let string = "Hello";
419 let bytes = b"Hello\0";
420 let string = EmptyOrFullCOctetString::<6>::from_str(string).unwrap();
421 assert_eq!(string.bytes, bytes);
422 }
423
424 #[test]
425 fn ok_len() {
426 let string = "Hello";
427 let string = EmptyOrFullCOctetString::<6>::from_str(string).unwrap();
428 assert_eq!(string.bytes.len(), 6);
429 assert_eq!(string.length(), 6);
430 }
431
432 #[test]
433 fn ok_empty() {
434 let string = "";
435 let bytes = b"\0";
436 let string = EmptyOrFullCOctetString::<6>::from_str(string).unwrap();
437 assert_eq!(string.bytes, bytes);
438 }
439
440 #[test]
441 fn ok_empty_len() {
442 let string = "";
443 let string = EmptyOrFullCOctetString::<6>::from_str(string).unwrap();
444 assert_eq!(string.bytes.len(), 1);
445 assert_eq!(string.length(), 1);
446 }
447 }
448
449 mod to_str {
450 use super::*;
451
452 #[test]
453 fn empty_ok() {
454 let bytes = b"\0";
455 let string = EmptyOrFullCOctetString::<6>::new(bytes).unwrap();
456 assert_eq!(string.to_str().unwrap(), "\0");
457 assert_eq!(string.to_string(), "\0");
458 }
459
460 #[test]
461 fn ok() {
462 let bytes = b"Hello\0";
463 let string = EmptyOrFullCOctetString::<6>::new(bytes).unwrap();
464 assert_eq!(string.to_str().unwrap(), "Hello\0");
465 assert_eq!(string.to_string(), "Hello\0");
466 }
467 }
468
469 mod decode {
470 use crate::decode::DecodeErrorKind;
471
472 use super::*;
473
474 #[test]
475 fn unexpected_eof_empty() {
476 let bytes = b"";
477 let error = EmptyOrFullCOctetString::<6>::decode(bytes).unwrap_err();
478
479 assert!(matches!(error.kind(), DecodeErrorKind::UnexpectedEof));
480 }
481
482 #[test]
483 fn not_null_terminated() {
484 let bytes = b"Hi";
485 let error = EmptyOrFullCOctetString::<2>::decode(bytes).unwrap_err();
486
487 assert!(matches!(
488 error.kind(),
489 DecodeErrorKind::COctetStringDecodeError(
490 COctetStringDecodeError::NotNullTerminated
491 )
492 ));
493 }
494
495 #[test]
496 fn too_many_bytes() {
497 let bytes = b"Hello\0";
498 let error = EmptyOrFullCOctetString::<5>::decode(bytes).unwrap_err();
499
500 assert!(matches!(
501 error.kind(),
502 DecodeErrorKind::COctetStringDecodeError(
503 COctetStringDecodeError::NotNullTerminated,
504 )
505 ));
506 }
507
508 #[test]
509 fn too_few_bytes() {
510 let bytes = b"Hel\0";
511 let error = EmptyOrFullCOctetString::<5>::decode(bytes).unwrap_err();
512
513 assert!(matches!(
514 error.kind(),
515 DecodeErrorKind::COctetStringDecodeError(COctetStringDecodeError::TooFewBytes {
516 actual: 4,
517 min: 5,
518 },)
519 ));
520 }
521
522 #[test]
523 fn not_ascii() {
524 let bytes = b"Hell\xF0\0";
525 let error = EmptyOrFullCOctetString::<6>::decode(bytes).unwrap_err();
526
527 assert!(matches!(
528 error.kind(),
529 DecodeErrorKind::COctetStringDecodeError(COctetStringDecodeError::NotAscii)
530 ));
531 }
532
533 #[test]
534 fn ok() {
535 let bytes = b"Hello\0World!";
536 let (string, size) = EmptyOrFullCOctetString::<6>::decode(bytes).unwrap();
537
538 assert_eq!(string.bytes, b"Hello\0");
539 assert_eq!(string.length(), 6);
540 assert_eq!(size, 6);
541 assert_eq!(&bytes[size..], b"World!");
542 }
543
544 #[test]
545 fn ok_empty() {
546 let bytes = b"\0World!";
547 let (string, size) = EmptyOrFullCOctetString::<6>::decode(bytes).unwrap();
548
549 assert_eq!(string.bytes, b"\0");
550 assert_eq!(string.length(), 1);
551 assert_eq!(size, 1);
552 assert_eq!(&bytes[size..], b"World!");
553 }
554 }
555}