Skip to main content

x690/
lib.rs

1//! # X.690 Encoding Rules Library
2//!
3//! This library provides comprehensive support for X.690 encoding rules, which define how ASN.1
4//! (Abstract Syntax Notation One) data structures are encoded for transmission and storage.
5//!
6//! ## Overview
7//!
8//! X.690 defines several encoding rules:
9//! - **BER (Basic Encoding Rules)**: The most flexible encoding, supporting both definite and indefinite lengths
10//! - **CER (Canonical Encoding Rules)**: A restricted form of BER that produces canonical encodings
11//! - **DER (Distinguished Encoding Rules)**: A restricted form of BER that produces unique encodings
12//!
13//! This library focuses on BER encoding and decoding, providing a complete implementation
14//! of the X.690 specification.
15//!
16//! ## Key Features
17//!
18//! - Complete BER encoding and decoding support
19//! - Support for all ASN.1 universal types
20//! - Efficient memory management with zero-copy operations where possible
21//! - Comprehensive error handling with detailed error information
22//! - Support for both definite and indefinite length encoding
23//! - Tag and length encoding/decoding utilities
24
25pub mod ber;
26#[cfg(feature = "der")]
27pub mod der;
28pub mod codec;
29pub mod parsing;
30pub(crate) mod utils;
31
32pub use crate::ber::*;
33pub use crate::codec::*;
34pub use crate::parsing::*;
35pub use crate::utils::primitive;
36
37use crate::utils::likely;
38use wildboar_asn1::error::{ASN1Error, ASN1ErrorCode, ASN1Result};
39use wildboar_asn1::{
40    ByteSlice, CharacterString, EmbeddedPDV, ExternalEncoding,
41    ExternalIdentification, GeneralizedTime,
42    PresentationContextSwitchingTypeIdentification, Tag, TagClass, TagNumber,
43    UTCTime,
44    UNIV_TAG_INTEGER,
45    UNIV_TAG_OBJECT_IDENTIFIER, UNIV_TAG_OCTET_STRING,
46    UNIV_TAG_OBJECT_DESCRIPTOR, BIT_STRING, BOOLEAN, DATE, DATE_TIME,
47    DURATION_EQUIVALENT, EXTERNAL, INTEGER, OBJECT_IDENTIFIER,
48    OCTET_STRING, REAL, RELATIVE_OID, TIME, TIME_OF_DAY,
49    UNIV_TAG_NULL,
50    UNIV_TAG_BOOLEAN,
51};
52use wildboar_asn1::{ENUMERATED, read_i64, DURATION, ComponentSpec, TagSelector};
53use std::borrow::Cow;
54use std::io::{Error, ErrorKind, Result, Write};
55use std::mem::size_of;
56use std::sync::Arc;
57use bytes::{Bytes, BytesMut, BufMut};
58
59/// Tag class bits for `UNIVERSAL` tags in X.690 encoding
60pub const X690_TAG_CLASS_UNIVERSAL: u8 = 0b0000_0000;
61
62/// Tag class bits for `APPLICATION` tags in X.690 encoding
63pub const X690_TAG_CLASS_APPLICATION: u8 = 0b0100_0000;
64
65/// Tag class bits for `CONTEXT` tags in X.690 encoding
66pub const X690_TAG_CLASS_CONTEXT: u8 = 0b1000_0000;
67
68/// Tag class bits for `PRIVATE` tags in X.690 encoding
69pub const X690_TAG_CLASS_PRIVATE: u8 = 0b1100_0000;
70
71/// Special `REAL` value constant for positive infinity
72pub const X690_SPECIAL_REAL_PLUS_INFINITY: u8 = 0b0000_0000;
73
74/// Special `REAL` value constant for negative infinity
75pub const X690_SPECIAL_REAL_MINUS_INFINITY: u8 = 0b0000_0001;
76
77/// Special `REAL` value constant for Not-a-Number (NaN)
78pub const X690_SPECIAL_REAL_NOT_A_NUMBER: u8 = 0b0000_0010;
79
80/// Special `REAL` value constant for negative zero
81pub const X690_SPECIAL_REAL_MINUS_ZERO: u8 = 0b0000_0011;
82
83/// Flag indicating a special `REAL` value
84pub const X690_REAL_SPECIAL: u8 = 0b0100_0000;
85
86/// Base encoding constant for base-10 `REAL` values
87pub const X690_REAL_BASE10: u8 = 0b0000_0000;
88
89/// Base encoding constant for binary `REAL` values
90pub const X690_REAL_BINARY: u8 = 0b1000_0000;
91
92/// Sign bit constant for positive `REAL` values
93pub const X690_REAL_POSITIVE: u8 = 0b0000_0000;
94
95/// Sign bit constant for negative `REAL` values
96pub const X690_REAL_NEGATIVE: u8 = 0b0100_0000;
97
98/// Bit mask for extracting the sign bit from `REAL` encoding
99pub const X690_REAL_SIGN_MASK: u8 = 0b0100_0000;
100
101/// Bit mask for extracting the base bits from `REAL` encoding
102pub const X690_REAL_BASE_MASK: u8 = 0b0011_0000;
103
104/// Base encoding constant for base-2 `REAL` values
105pub const X690_REAL_BASE_2: u8 = 0b0000_0000;
106
107/// Base encoding constant for base-8 `REAL` values
108pub const X690_REAL_BASE_8: u8 = 0b0001_0000;
109
110/// Base encoding constant for base-16 `REAL` values
111pub const X690_REAL_BASE_16: u8 = 0b0010_0000;
112
113/// Reserved base encoding constant for `REAL` values
114pub const X690_REAL_BASE_RESERVED: u8 = 0b0011_0000;
115
116/// Bit mask for extracting binary scaling factor from `REAL` encoding
117pub const X690_REAL_BINARY_SCALING_MASK: u8 = 0b0000_1100;
118
119/// Bit mask for extracting exponent format from `REAL` encoding
120pub const X690_REAL_EXPONENT_FORMAT_MASK: u8 = 0b0000_0011;
121
122/// Exponent format constant for 1-octet exponent
123pub const X690_REAL_EXPONENT_FORMAT_1_OCTET: u8 = 0b0000_0000;
124
125/// Exponent format constant for 2-octet exponent
126pub const X690_REAL_EXPONENT_FORMAT_2_OCTET: u8 = 0b0000_0001;
127
128/// Exponent format constant for 3-octet exponent
129pub const X690_REAL_EXPONENT_FORMAT_3_OCTET: u8 = 0b0000_0010;
130
131/// Exponent format constant for variable-length exponent
132pub const X690_REAL_EXPONENT_FORMAT_VAR_OCTET: u8 = 0b0000_0011;
133
134/// ISO 6093 NR1 format constant for `REAL` encoding
135pub const X690_REAL_NR1: u8 = 1;
136
137/// ISO 6093 NR2 format constant for `REAL` encoding
138pub const X690_REAL_NR2: u8 = 2;
139
140/// ISO 6093 NR3 format constant for `REAL` encoding
141pub const X690_REAL_NR3: u8 = 3;
142
143/// Represents the length of an X.690 encoded element
144///
145/// In X.690 encoding, lengths can be either definite (a specific number of octets)
146/// or indefinite (marked with a special value and terminated by end-of-content markers).
147#[derive(Clone, Debug, Hash, Copy, PartialEq, Eq)]
148pub enum X690Length {
149    /// Definite length with a specific number of octets
150    Definite(usize),
151    /// Indefinite length, terminated by end-of-content markers
152    Indefinite,
153}
154
155/// Represents the value content of an X.690 encoded element
156///
157/// X.690 values can be stored in different forms depending on how they were created
158/// and whether they need to be serialized for transmission.
159#[derive(Clone, Debug, Hash)]
160pub enum X690Value {
161    /// A primitive value stored as raw bytes
162    Primitive(Bytes),
163    /// A constructed value containing child elements
164    Constructed(Arc<Vec<X690Element>>),
165    /// A value that has been serialized to bytes (for lazy decoding or faster encoding)
166    Serialized(Bytes),
167}
168
169impl X690Value {
170
171    /// Returns the length of the content octets in bytes
172    ///
173    /// For primitive values, this is the length of the raw bytes.
174    /// For constructed values, this is the sum of all child element lengths.
175    /// For serialized values, this decodes the serialized data to determine the length.
176    pub fn len(&self) -> usize {
177        match self {
178            X690Value::Primitive(v) => v.len(),
179            X690Value::Constructed(components) => {
180                let mut sum: usize = 0;
181                for component in components.iter() {
182                    sum += component.len();
183                }
184                sum
185            },
186            X690Value::Serialized(v) => {
187                match BER.decode_from_slice(&v) {
188                    Ok((_, el)) => el.len(),
189                    Err(_) => return 0,
190                }
191            }
192        }
193    }
194
195    /// Creates a constructed value from a single explicit element
196    ///
197    /// This is used when an element needs to be wrapped in an explicit tag.
198    #[inline]
199    pub fn from_explicit(inner: X690Element) -> Self {
200        X690Value::Constructed(Arc::new(Vec::from([ inner ])))
201    }
202
203    /// Returns the components of a constructed value
204    ///
205    /// For constructed values, returns the child elements.
206    /// For serialized values, decodes the serialized data and returns the components.
207    /// For primitive values, returns an error.
208    pub fn components(&self) -> ASN1Result<Arc<Vec<X690Element>>> {
209        match self {
210            X690Value::Constructed(components) => Ok(components.clone()),
211            X690Value::Serialized(v) => {
212                let (_, el) = BER.decode_from_slice(&v)?;
213                el.value.components()
214            },
215            _ => Err(ASN1Error::new(ASN1ErrorCode::invalid_construction)),
216        }
217    }
218
219}
220
221/// Represents a complete X.690 encoded element with tag and value
222///
223/// An `X690Element` contains a tag that identifies the type and class of the element,
224/// and a value that contains the actual data. The value can be primitive (raw bytes),
225/// constructed (containing child elements), or serialized (encoded bytes).
226#[derive(Clone, Debug, Hash)]
227pub struct X690Element {
228    /// The tag identifying the type and class of this element
229    pub tag: Tag,
230    /// The value content of this element
231    pub value: X690Value,
232}
233
234impl X690Element {
235
236    /// Creates a new `X690Element` with the specified tag and value
237    #[inline]
238    pub const fn new(tag: Tag, value: X690Value) -> X690Element {
239        X690Element { tag, value }
240    }
241
242    /// Make a new `NULL` encoding.
243    #[inline]
244    pub const fn null() -> X690Element {
245        X690Element {
246            tag: Tag::new(TagClass::UNIVERSAL, UNIV_TAG_NULL),
247            value: X690Value::Primitive(Bytes::new()),
248        }
249    }
250
251    /// Make a new `TRUE` encoding.
252    #[inline]
253    pub const fn boolean_true() -> X690Element {
254        X690Element {
255            tag: Tag::new(TagClass::UNIVERSAL, UNIV_TAG_BOOLEAN),
256            value: X690Value::Primitive(Bytes::from_static(&[ 0xff ])),
257        }
258    }
259
260    /// Make a new `FALSE` encoding.
261    #[inline]
262    pub const fn boolean_false() -> X690Element {
263        X690Element {
264            tag: Tag::new(TagClass::UNIVERSAL, UNIV_TAG_BOOLEAN),
265            value: X690Value::Primitive(Bytes::from_static(&[ 0x00 ])),
266        }
267    }
268
269    /// Returns the total length of this element in bytes when encoded
270    ///
271    /// This includes the tag bytes, length bytes, and value bytes.
272    pub fn len(&self) -> usize {
273        let tag_length: usize = get_written_x690_tag_length(self.tag.tag_number);
274        let value_length = self.value.len();
275        let length_length: usize = get_written_x690_length_length(value_length);
276        let ret = tag_length + length_length + value_length;
277        ret
278    }
279
280    /// Returns true if this element is constructed (contains child elements)
281    ///
282    /// For serialized values, this checks the constructed bit in the tag.
283    /// For constructed values, this always returns true.
284    /// For primitive values, this always returns false.
285    #[inline]
286    pub fn is_constructed (&self) -> bool {
287        if let X690Value::Serialized(v) = &self.value {
288            return v.get(0).is_some_and(|b| (*b & 0b0010_0000) == 0b0010_0000);
289        }
290        if let X690Value::Constructed(_) = self.value {
291            true
292        } else {
293            false
294        }
295    }
296
297    /// Returns the components of this element if it is constructed
298    ///
299    /// This is a convenience method that delegates to the value's [`X690Value::components`] method.
300    #[inline]
301    pub fn components (&self) -> ASN1Result<Arc<Vec<X690Element>>> {
302        self.value.components()
303    }
304
305    /// Returns the inner element if this is an explicit wrapper
306    ///
307    /// For explicit tagged values, this returns the single child element.
308    /// For other values, this returns an error.
309    pub fn inner(&self) -> ASN1Result<X690Element> {
310        match &self.value {
311            X690Value::Constructed(components) => {
312                if components.len() != 1 {
313                    return Err(self.to_asn1_error(ASN1ErrorCode::invalid_construction));
314                }
315                Ok(components[0].clone())
316            },
317            X690Value::Serialized(v) => {
318                let (_, el) = BER.decode_from_slice(&v)?;
319                el.inner()
320            },
321            _ => Err(self.to_asn1_error(ASN1ErrorCode::invalid_construction)),
322        }
323    }
324
325    /// Returns the content octets of this element
326    ///
327    /// For primitive values, returns the raw bytes.
328    /// For constructed values, serializes the child elements and returns the bytes.
329    /// For serialized values, decodes and returns the content octets.
330    pub fn content_octets <'a> (&'a self) -> ASN1Result<Cow<'a, [u8]>> {
331        match &self.value {
332            X690Value::Primitive(v) => Ok(Cow::Borrowed(&v)),
333            X690Value::Constructed(_) => {
334                let mut output = BytesMut::with_capacity(self.len()).writer();
335                x690_write_value(&mut output, &self.value)?;
336                Ok(Cow::Owned(output.into_inner().into()))
337            },
338            X690Value::Serialized(v) => {
339                let (_, el) = BER.decode_from_slice(v).unwrap();
340                match el.value {
341                    X690Value::Primitive(inner) => Ok(Cow::Owned(inner.to_vec())),
342                    X690Value::Constructed(_) => {
343                        let mut output = BytesMut::with_capacity(el.len()).writer();
344                        x690_write_value(&mut output, &el.value)?;
345                        Ok(Cow::Owned(output.into_inner().into()))
346                    },
347                    _ => panic!("ASN.1 / X.690 decoding returned serialized value"),
348                }
349            }
350        }
351    }
352
353    /// Creates an `ASN1Error` with information from this element
354    ///
355    /// This is useful for creating detailed error messages that include
356    /// information about the element that caused the error.
357    #[inline]
358    pub fn to_asn1_error (&self, errcode: ASN1ErrorCode) -> ASN1Error {
359        ASN1Error {
360            error_code: errcode,
361            component_name: None,
362            tag: Some(Tag::new(self.tag.tag_class, self.tag.tag_number)),
363            length: Some(self.len()),
364            constructed: Some(self.is_constructed()),
365            value_preview: None,
366            bytes_read: None,
367            values_read: None,
368            err_source: None,
369        }
370    }
371
372    /// Creates an `ASN1Error` with information from this element and a component name
373    ///
374    /// This is useful for creating detailed error messages that include
375    /// information about the element and the specific component that caused the error.
376    pub fn to_asn1_err_named (&self, errcode: ASN1ErrorCode, name: &str) -> ASN1Error {
377        let mut e = self.to_asn1_error(errcode);
378        e.component_name = Some(name.to_string());
379        e
380    }
381
382    /// Returns `true` if this element is empty
383    ///
384    /// For primitive values, checks if the byte length is zero.
385    /// For constructed values, checks if there are no child elements.
386    /// For serialized values, checks if the serialized data is minimal (just tag and length).
387    #[inline]
388    pub fn is_empty (&self) -> bool {
389        match &self.value {
390            X690Value::Primitive(v) => v.len() == 0,
391            X690Value::Constructed(components) => components.len() == 0,
392            X690Value::Serialized(v) => v.len() <= 2,
393        }
394    }
395
396    /// Returns an iterator that iterates over the primitive content octets of
397    /// the constituent elements of this element, recursively.
398    /// 
399    /// In other words a `UTF8String` encoding that is structed like so:
400    /// 
401    /// ```text
402    /// [UNIV 12]
403    ///     [UNIV 4] "hello"
404    ///     [UNIV 4]
405    ///         [UNIV 4] " "
406    ///     [UNIV 4] "world"
407    /// ```
408    /// 
409    /// Will result in the content octets for "hello", " ", and "world" being
410    /// returned from the iterator, in that order.
411    /// 
412    #[inline]
413    pub fn iter_deconstruction<'a>(&'a self) -> DeconstructionIterator<'a> {
414        DeconstructionIterator::new(self)
415    }
416
417}
418
419impl From<i8> for X690Element {
420    /// Converts an `i8` to an `X690Element` by encoding it as an `INTEGER`
421    #[inline]
422    fn from(value: i8) -> Self {
423        BER.encode_i8(value).unwrap()
424    }
425}
426
427impl From<i16> for X690Element {
428    /// Converts an `i16` to an `X690Element` by encoding it as an `INTEGER`
429    #[inline]
430    fn from(value: i16) -> Self {
431        BER.encode_i16(value).unwrap()
432    }
433}
434
435impl From<i32> for X690Element {
436    /// Converts an `i32` to an `X690Element` by encoding it as an `INTEGER`
437    #[inline]
438    fn from(value: i32) -> Self {
439        BER.encode_i32(value).unwrap()
440    }
441}
442
443impl From<i64> for X690Element {
444    /// Converts an `i64` to an `X690Element` by encoding it as an `INTEGER`
445    #[inline]
446    fn from(value: i64) -> Self {
447        BER.encode_i64(value).unwrap()
448    }
449}
450
451impl From<u8> for X690Element {
452    /// Converts a `u8` to an `X690Element` by encoding it as an `INTEGER`
453    #[inline]
454    fn from(value: u8) -> Self {
455        BER.encode_u8(value).unwrap()
456    }
457}
458
459impl From<u16> for X690Element {
460    /// Converts a `u16` to an `X690Element` by encoding it as an `INTEGER`
461    #[inline]
462    fn from(value: u16) -> Self {
463        BER.encode_u16(value).unwrap()
464    }
465}
466
467impl From<u32> for X690Element {
468    /// Converts a `u32` to an `X690Element` by encoding it as an `INTEGER`
469    #[inline]
470    fn from(value: u32) -> Self {
471        BER.encode_u32(value).unwrap()
472    }
473}
474
475impl From<u64> for X690Element {
476    /// Converts a `u64` to an ``X690Element`` by encoding it as an `INTEGER`
477    #[inline]
478    fn from(value: u64) -> Self {
479        BER.encode_u64(value).unwrap()
480    }
481}
482
483impl From<OBJECT_IDENTIFIER> for X690Element {
484    /// Converts an `OBJECT_IDENTIFIER` to an `X690Element` by encoding it
485    #[inline]
486    fn from(value: OBJECT_IDENTIFIER) -> Self {
487        X690Element::from(&value)
488    }
489}
490
491impl From<&OBJECT_IDENTIFIER> for X690Element {
492    /// Converts a reference to an `OBJECT_IDENTIFIER` to an `X690Element` by encoding it
493    #[inline]
494    fn from(value: &OBJECT_IDENTIFIER) -> Self {
495        BER.encode_object_identifier(value).unwrap()
496    }
497}
498
499impl From<bool> for X690Element {
500    /// Converts a bool to an X690Element by encoding it as a BOOLEAN
501    #[inline]
502    fn from(value: bool) -> Self {
503        BER.encode_boolean(&value).unwrap()
504    }
505}
506
507impl From<DATE> for X690Element {
508    /// Converts a `DATE` to an `X690Element` by encoding it
509    #[inline]
510    fn from(value: DATE) -> Self {
511        BER.encode_date(&value).unwrap()
512    }
513}
514
515impl From<TIME_OF_DAY> for X690Element {
516    /// Converts a `TIME_OF_DAY` to an `X690Element` by encoding it
517    #[inline]
518    fn from(value: TIME_OF_DAY) -> Self {
519        BER.encode_time_of_day(&value).unwrap()
520    }
521}
522
523impl From<DATE_TIME> for X690Element {
524    /// Converts a `DATE_TIME` to an `X690Element` by encoding it
525    #[inline]
526    fn from(value: DATE_TIME) -> Self {
527        BER.encode_date_time(&value).unwrap()
528    }
529}
530
531impl From<TIME> for X690Element {
532    /// Converts a `TIME` to an `X690Element` by encoding it
533    #[inline]
534    fn from(value: TIME) -> Self {
535        BER.encode_time(&value).unwrap()
536    }
537}
538
539impl From<DURATION> for X690Element {
540    /// Converts a `DURATION` to an `X690Element` by encoding it
541    #[inline]
542    fn from(value: DURATION) -> Self {
543        BER.encode_duration(&value).unwrap()
544    }
545}
546
547impl TryInto<i8> for X690Element {
548    type Error = ASN1Error;
549    /// Attempts to decode an X690Element as an `i8` `INTEGER`
550    #[inline]
551    fn try_into(self) -> ASN1Result<i8> {
552        BER.decode_i8(&self)
553    }
554}
555
556impl TryInto<i16> for X690Element {
557    type Error = ASN1Error;
558    /// Attempts to decode an X690Element as an `i16` `INTEGER`
559    #[inline]
560    fn try_into(self) -> ASN1Result<i16> {
561        BER.decode_i16(&self)
562    }
563}
564
565impl TryInto<i32> for X690Element {
566    type Error = ASN1Error;
567    /// Attempts to decode an X690Element as an `i32` `INTEGER`
568    #[inline]
569    fn try_into(self) -> ASN1Result<i32> {
570        BER.decode_i32(&self)
571    }
572}
573
574impl TryInto<i64> for X690Element {
575    type Error = ASN1Error;
576    /// Attempts to decode an X690Element as an `i64` `INTEGER`
577    #[inline]
578    fn try_into(self) -> ASN1Result<i64> {
579        BER.decode_i64(&self)
580    }
581}
582
583impl TryInto<i128> for X690Element {
584    type Error = ASN1Error;
585    /// Attempts to decode an X690Element as an `i128` `INTEGER`
586    #[inline]
587    fn try_into(self) -> ASN1Result<i128> {
588        BER.decode_i128(&self)
589    }
590}
591
592impl TryInto<u8> for X690Element {
593    type Error = ASN1Error;
594    /// Attempts to decode an X690Element as a `u8` `INTEGER`
595    #[inline]
596    fn try_into(self) -> ASN1Result<u8> {
597        BER.decode_u8(&self)
598    }
599}
600
601impl TryInto<u16> for X690Element {
602    type Error = ASN1Error;
603    /// Attempts to decode an X690Element as a `u16` `INTEGER`
604    #[inline]
605    fn try_into(self) -> ASN1Result<u16> {
606        BER.decode_u16(&self)
607    }
608}
609
610impl TryInto<u32> for X690Element {
611    type Error = ASN1Error;
612    /// Attempts to decode an X690Element as a `u32` `INTEGER`
613    #[inline]
614    fn try_into(self) -> ASN1Result<u32> {
615        BER.decode_u32(&self)
616    }
617}
618
619impl TryInto<u64> for X690Element {
620    type Error = ASN1Error;
621    /// Attempts to decode an X690Element as a `u64` `INTEGER`
622    #[inline]
623    fn try_into(self) -> ASN1Result<u64> {
624        BER.decode_u64(&self)
625    }
626}
627
628impl TryInto<u128> for X690Element {
629    type Error = ASN1Error;
630    /// Attempts to decode an X690Element as a `u128` `INTEGER`
631    #[inline]
632    fn try_into(self) -> ASN1Result<u128> {
633        BER.decode_u128(&self)
634    }
635}
636
637impl TryInto<BOOLEAN> for X690Element {
638    type Error = ASN1Error;
639    /// Attempts to decode an X690Element as a `BOOLEAN`
640    #[inline]
641    fn try_into(self) -> ASN1Result<BOOLEAN> {
642        BER.decode_boolean(&self)
643    }
644}
645
646impl PartialEq for X690Element {
647    /// Compares two X690Elements for equality
648    ///
649    /// For serialized values, this decodes them first before comparison.
650    /// Primitive values are compared by their raw bytes.
651    /// Constructed values are compared by their child elements.
652    fn eq(&self, other: &Self) -> bool {
653        // Helper to decode if serialized, else return reference to self
654        fn as_decoded<'a>(el: &'a X690Element) -> Cow<'a, X690Element> {
655            match &el.value {
656                X690Value::Serialized(bytes) => {
657                    match BER.decode_from_slice(bytes) {
658                        Ok((_, decoded)) => Cow::Owned(decoded),
659                        Err(_) => Cow::Borrowed(el), // fallback: treat as not equal
660                    }
661                }
662                _ => Cow::Borrowed(el),
663            }
664        }
665
666        let left = as_decoded(self);
667        let right = as_decoded(other);
668
669        match (&left.value, &right.value) {
670            (X690Value::Primitive(a), X690Value::Primitive(b)) => a == b,
671            (X690Value::Constructed(a), X690Value::Constructed(b)) => {
672                if a.len() != b.len() {
673                    return false;
674                }
675                a.iter().zip(b.iter()).all(|(x, y)| x == y)
676            }
677            (X690Value::Primitive(_), _) | (X690Value::Constructed(_), _) | (_, X690Value::Primitive(_)) | (_, X690Value::Constructed(_)) => false,
678            // Should not reach here, as all Serialized are decoded above
679            _ => false,
680        }
681    }
682}
683
684impl Eq for X690Element {}
685
686/// Decodes an X.690 tag from a byte slice
687///
688/// Returns a tuple containing:
689/// - The number of bytes read
690/// - The decoded tag
691/// - Whether the tag is constructed
692///
693/// This function handles both short and long tag formats as specified in X.690.
694pub fn x690_decode_tag(bytes: ByteSlice) -> ASN1Result<(usize, Tag, bool)> {
695    if bytes.len() == 0 {
696        return Err(ASN1Error::new(ASN1ErrorCode::tlv_truncated));
697    }
698    let mut bytes_read = 1;
699    let tag_class = match (bytes[0] & 0b1100_0000) >> 6 {
700        0 => TagClass::UNIVERSAL,
701        1 => TagClass::APPLICATION,
702        2 => TagClass::CONTEXT,
703        3 => TagClass::PRIVATE,
704        _ => panic!("Impossible tag class"),
705    };
706    let constructed = (bytes[0] & 0b0010_0000) > 0;
707    let mut tag_number: TagNumber = 0;
708
709    if (bytes[0] & 0b00011111) == 0b00011111 {
710        // If it is a long tag...
711        for byte in bytes[1..].iter() {
712            let final_byte: bool = ((*byte) & 0b1000_0000) == 0;
713            if (tag_number > 0) && !final_byte {
714                // tag_number > 0 means we've already processed one byte.
715                // Tag encoded on more than 14 bits / two bytes.
716                return Err(ASN1Error::new(ASN1ErrorCode::tag_too_big));
717            }
718            let seven_bits = ((*byte) & 0b0111_1111) as u16;
719            if !final_byte && (seven_bits == 0) {
720                // You cannot encode a long tag with padding bytes.
721                return Err(ASN1Error::new(ASN1ErrorCode::padding_in_tag_number));
722            }
723            tag_number <<= 7;
724            tag_number += seven_bits;
725            bytes_read += 1;
726            if final_byte {
727                break;
728            }
729        }
730        if tag_number <= 30 {
731            // This could have been encoded in short form.
732            return Err(ASN1Error::new(ASN1ErrorCode::tag_number_could_have_used_short_form));
733        }
734    } else {
735        tag_number = (bytes[0] & 0b00011111) as TagNumber;
736    }
737
738    let tag = Tag::new(tag_class, tag_number);
739    Ok((bytes_read, tag, constructed))
740}
741
742/// Calculates the total length of tag and length bytes in an X.690 encoding
743///
744/// This function examines the first few bytes to determine how many bytes
745/// are used for the tag and length encoding, without actually decoding the values.
746pub fn get_x690_tag_and_length_length(bytes: ByteSlice) -> usize {
747    if bytes.len() == 0 {
748        return 0;
749    }
750    let mut len: usize = 1;
751    if (bytes[0] & 0b00011111) == 0b00011111 {
752        // If it is a long tag...
753        for byte in bytes[1..].iter() {
754            len += 1; // Even the byte without the continuation flag set should be counted.
755            if ((*byte) & 0b1000_0000) == 0 {
756                break;
757            }
758        }
759    }
760    if len >= bytes.len() {
761        return len;
762    }
763    let length_byte_0 = bytes[len - 1];
764    len += 1;
765    if (length_byte_0 & 0b1000_0000) == 0 {
766        // Short definite form or indefinite form.
767        return len;
768    }
769    (length_byte_0 & 0b0111_1111) as usize
770}
771
772/// Calculates the number of bytes needed to encode a number in base-128 format
773///
774/// Base-128 encoding is used for long tag numbers and other variable-length `INTEGER`s
775/// in X.690 encoding.
776const fn base_128_len(num: u32) -> usize {
777    if likely(num < 128) {
778        return 1;
779    }
780    let mut l = 0;
781    let mut i = num;
782    while i > 0 {
783        l += 1;
784        i >>= 7;
785    }
786    return l;
787}
788
789/// Writes a number in base-128 format to a writer
790///
791/// Base-128 encoding uses 7 bits per byte with a continuation bit in the high bit.
792/// This is used for encoding long tag numbers and other variable-length `INTEGER`s.
793///
794/// Returns the number of bytes written.
795fn write_base_128<W>(output: &mut W, mut num: u32) -> Result<usize>
796where
797    W: Write,
798{
799    #[cfg(feature = "likely_stable")]
800    if likely(num < 128) {
801        return output.write(&[num as u8]);
802    }
803
804    // A u32 can take up to 5 bytes.
805    let mut encoded: [u8; 5] = [0; 5];
806    let mut byte_count: usize = 0;
807    while num > 0b0111_1111 {
808        encoded[byte_count] = (num & 0b0111_1111) as u8 | 0b1000_0000;
809        byte_count += 1;
810        num >>= 7;
811    }
812    encoded[byte_count] = num as u8;
813    output.write(&encoded[0..byte_count+1])
814}
815
816/// Calculates the number of bytes needed to encode a tag number
817///
818/// Tag numbers less than 31 use the short form (1 byte).
819/// Tag numbers 31 and above use the long form with base-128 encoding.
820pub const fn get_written_x690_tag_length(tagnum: TagNumber) -> usize {
821    if tagnum < 31 {
822        // See ITU Rec. X.690 (2021), Section 8.1.2.4.
823        return 1;
824    }
825    base_128_len(tagnum as u32) + 1
826}
827
828/// Calculates the number of bytes needed to encode a length value
829///
830/// Lengths 0-127 use the short form (1 byte).
831/// Longer lengths use the long form with a length indicator byte followed by the length value.
832pub const fn get_written_x690_length_length(len: usize) -> usize {
833    if len <= 127 {
834        // See ITU Rec. X.690 (2021), Section 8.1.3.3, "NOTE"
835        return 1;
836    }
837    let octets_needed: usize = match len {
838        0..=255 => 1,
839        256..=65535 => 2,
840        65536..=16777215 => 3,
841        16777216..=4294967295 => 4,
842        _ => return 5, // This is 4GB * 255. It's more than enough for anything.
843    };
844    octets_needed + 1
845}
846
847/// Writes an X.690 tag to a writer
848///
849/// This function handles both short and long tag formats as specified in X.690.
850/// The tag includes the class, constructed bit, and tag number.
851///
852/// Returns the number of bytes written.
853pub fn x690_write_tag<W>(
854    output: &mut W,
855    class: TagClass,
856    constructed: bool,
857    tagnum: TagNumber,
858) -> Result<usize>
859where
860    W: Write,
861{
862    let k: u8 = match class {
863        TagClass::UNIVERSAL => X690_TAG_CLASS_UNIVERSAL,
864        TagClass::APPLICATION => X690_TAG_CLASS_APPLICATION,
865        TagClass::CONTEXT => X690_TAG_CLASS_CONTEXT,
866        TagClass::PRIVATE => X690_TAG_CLASS_PRIVATE,
867    };
868    if tagnum < 31 {
869        // See ITU Rec. X.690 (2021), Section 8.1.2.4.
870        return output.write(&[k
871            | if constructed {
872                0b0010_0000
873            } else {
874                0b0000_0000
875            }
876            | tagnum as u8]);
877    } else {
878        let first_byte_result = output.write(&[k
879            | if constructed {
880                0b0010_0000
881            } else {
882                0b0000_0000
883            }
884            | 0b0001_1111u8]);
885        if let Err(e) = first_byte_result {
886            return Err(e);
887        }
888        return write_base_128(output, tagnum.into());
889    }
890}
891
892/// Writes an X.690 length to a writer
893///
894/// This function handles both short and long length formats as specified in X.690.
895/// Lengths 0-127 use the short form, longer lengths use the long form.
896///
897/// Returns the number of bytes written.
898pub fn x690_write_length<W>(output: &mut W, length: usize) -> Result<usize>
899where
900    W: Write,
901{
902    if length <= 127 {
903        // See ITU Rec. X.690 (2021), Section 8.1.3.3, "NOTE"
904        return output.write(&[length as u8]);
905    } else {
906        // Calculate num of octets needed.
907        // write 0b1000_0000 | octets needed
908        let octets_needed: u8 = match length {
909            0..=255 => 1,
910            256..=65535 => 2,
911            65536..=16777215 => 3,
912            16777216..=4294967295 => 4,
913            _ => return Err(Error::from(ErrorKind::Unsupported)),
914        };
915        let length_bytes = length.to_be_bytes();
916        output.write(&[0b1000_0000 | octets_needed])?;
917        output.write(&length_bytes[std::mem::size_of::<usize>()-octets_needed as usize..])
918            .map(|n| n + 1)
919    }
920}
921
922/// Writes a `BOOLEAN` value in X.690 format
923///
924/// `BOOLEAN` values are encoded as a single octet: 0xFF for true, 0x00 for false.
925///
926/// Returns the number of bytes written.
927#[inline]
928pub fn x690_write_boolean_value<W>(output: &mut W, value: &BOOLEAN) -> Result<usize>
929where
930    W: Write,
931{
932    if *value {
933        return output.write(&[0xFF]);
934    } else {
935        return output.write(&[0x00]);
936    }
937}
938
939/// Writes an `INTEGER` value in X.690 format
940///
941/// `INTEGER` values are written as raw bytes in big-endian format.
942///
943/// Returns the number of bytes written.
944#[inline]
945pub fn x690_write_integer_value<W>(output: &mut W, value: &INTEGER) -> Result<usize>
946where
947    W: Write,
948{
949    if value.len() == 0 {
950        return Err(std::io::Error::from(ErrorKind::InvalidData));
951    }
952    if value.len() == 1 {
953        return output.write(value);
954    }
955    if value[0] == 0x00 && (value[1] & 0b1000_0000) == 0 {
956        return Err(std::io::Error::from(ErrorKind::InvalidData));
957    }
958    if value[0] == 0xFF && (value[1] & 0b1000_0000) > 0 {
959        return Err(std::io::Error::from(ErrorKind::InvalidData));
960    }
961    output.write(value)
962}
963
964/// Writes an i64 value in X.690 `INTEGER` format
965///
966/// This function handles the encoding of i64 values as `INTEGER` types,
967/// including proper handling of sign extension and padding.
968///
969/// Returns the number of bytes written.
970pub fn x690_write_i64_value<W>(output: &mut W, value: i64) -> Result<usize>
971where
972    W: Write,
973{
974    let bytes: [u8; 8] = value.to_be_bytes();
975    let padding_byte: u8 = if value >= 0 { 0x00 } else { 0xFF };
976    let mut number_of_padding_bytes: usize = 0;
977    for byte in bytes {
978        if byte == padding_byte {
979            number_of_padding_bytes += 1;
980        } else {
981            break;
982        }
983    }
984    let mut bytes_written: usize = 0;
985    if (number_of_padding_bytes == size_of::<i64>())
986        || (value >= 0 && ((bytes[number_of_padding_bytes] & 0b1000_0000) > 0))
987        || (value < 0 && ((bytes[number_of_padding_bytes] & 0b1000_0000) == 0)) {
988        bytes_written += output.write(&[padding_byte])?;
989    }
990    bytes_written += output.write(&(bytes[number_of_padding_bytes..size_of::<i64>()]))?;
991    Ok(bytes_written)
992}
993
994/// Writes an `ENUMERATED` value in X.690 format
995///
996/// `ENUMERATED` values are encoded the same as `INTEGER` values.
997///
998/// Returns the number of bytes written.
999#[inline]
1000pub fn x690_write_enum_value<W>(output: &mut W, value: &ENUMERATED) -> Result<usize>
1001where
1002    W: Write,
1003{
1004    x690_write_i64_value(output, *value)
1005}
1006
1007/// Writes a `BIT STRING` value in X.690 format
1008///
1009/// `BIT STRING` values include a trailing bits count byte followed by the actual bits.
1010///
1011/// Returns the number of bytes written.
1012pub fn x690_write_bit_string_value<W>(output: &mut W, value: &BIT_STRING) -> Result<usize>
1013where
1014    W: Write,
1015{
1016    let trailing_bits = value.get_trailing_bits_count();
1017    output.write(&[trailing_bits])?;
1018    if trailing_bits == 0 {
1019        let bytes_written = output.write(value.get_bytes_ref())?;
1020        return Ok(bytes_written + 1);
1021    }
1022    // Otherwise, we check if the trailing bits are set and fix that.
1023    let maybe_last_byte = value.get_bytes_ref().last();
1024    let der_violated;
1025    let bytes = value.get_bytes_ref();
1026    let correct_last_byte: u8;
1027    if let Some(last_byte) = maybe_last_byte {
1028        let trailing_bits_mask = !(0xFFu8 << trailing_bits);
1029        der_violated = (last_byte & trailing_bits_mask) > 0;
1030        correct_last_byte = last_byte & (0xFFu8 << trailing_bits);
1031    } else {
1032        return Err(std::io::Error::from(ErrorKind::InvalidData));
1033    }
1034
1035    // No violation? Just write the whole thing.
1036    if likely(!der_violated) {
1037        let bytes_written = output.write(value.get_bytes_ref())?;
1038        return Ok(bytes_written + 1);
1039    }
1040
1041    debug_assert!(maybe_last_byte.is_some());
1042    let mut bytes_written = output.write(&bytes[..bytes.len() - 1])?;
1043    bytes_written += output.write(&[ correct_last_byte ])?;
1044    Ok(bytes_written + 1)
1045}
1046
1047/// Writes an `OCTET STRING` value in X.690 format
1048///
1049/// `OCTET STRING` values are written as raw bytes.
1050///
1051/// Returns the number of bytes written.
1052#[inline]
1053pub fn x690_write_octet_string_value<W>(output: &mut W, value: &OCTET_STRING) -> Result<usize>
1054where
1055    W: Write,
1056{
1057    output.write(value)
1058}
1059
1060/// Writes an `OBJECT IDENTIFIER` value in X.690 format
1061///
1062/// `OBJECT IDENTIFIER` values are encoded using the X.690 encoding format.
1063///
1064/// Returns the number of bytes written.
1065#[inline]
1066pub fn x690_write_object_identifier_value<W>(
1067    output: &mut W,
1068    value: &OBJECT_IDENTIFIER,
1069) -> Result<usize>
1070where
1071    W: Write,
1072{
1073    output.write(value.as_x690_slice())
1074}
1075
1076/// Writes an `ObjectDescriptor` value in X.690 format
1077///
1078/// `ObjectDescriptor` values are written as UTF-8 encoded strings.
1079///
1080/// Returns the number of bytes written.
1081#[inline]
1082pub fn x690_write_object_descriptor_value<W>(
1083    output: &mut W,
1084    value: &str,
1085) -> Result<usize>
1086where
1087    W: Write,
1088{
1089    output.write(value.as_bytes())
1090}
1091
1092/// Encode the components of an `EXTERNAL` value as X.690-encoded elements
1093///
1094/// This function encodes the components of an `EXTERNAL` value as X.690-encoded elements.
1095/// It handles the encoding of the identification, data value descriptor, and data value.
1096///
1097/// # Arguments
1098/// * `value` - The `EXTERNAL` value to encode
1099///
1100/// # Returns
1101/// A vector of X.690-encoded elements representing the components of the `EXTERNAL` value
1102///
1103/// To be a complete `EXTERNAL` value, these MUST be contained within a "parent" element
1104/// having tag `[UNIVERSAL 8]` and it MUST be constructed.
1105pub fn x690_encode_external_components (value: &EXTERNAL) -> Result<Vec<X690Element>> {
1106    let mut inner_elements: Vec<X690Element> = Vec::with_capacity(4);
1107    match &value.identification {
1108        ExternalIdentification::syntax(oid) => {
1109            let mut bytes = BytesMut::new().writer();
1110            x690_write_object_identifier_value(&mut bytes, &oid)?;
1111            let element = X690Element::new(
1112                Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OBJECT_IDENTIFIER),
1113                X690Value::Primitive(bytes.into_inner().into()),
1114            );
1115            inner_elements.push(element);
1116        }
1117        ExternalIdentification::presentation_context_id(pci) => {
1118            let mut bytes = BytesMut::new().writer();
1119            x690_write_integer_value(&mut bytes, pci)?;
1120            let element = X690Element::new(
1121                Tag::new(TagClass::UNIVERSAL, UNIV_TAG_INTEGER),
1122                X690Value::Primitive(bytes.into_inner().into()),
1123            );
1124            inner_elements.push(element);
1125        }
1126        ExternalIdentification::context_negotiation(cn) => {
1127            let mut direct_ref_bytes = BytesMut::new().writer();
1128            x690_write_object_identifier_value(&mut direct_ref_bytes, &cn.transfer_syntax)?;
1129            let direct_ref_element = X690Element::new(
1130                Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OBJECT_IDENTIFIER),
1131                X690Value::Primitive(direct_ref_bytes.into_inner().into()),
1132            );
1133            inner_elements.push(direct_ref_element);
1134            let mut indirect_ref_bytes = BytesMut::new().writer();
1135            x690_write_integer_value(&mut indirect_ref_bytes, &cn.presentation_context_id)?;
1136            let indirect_ref_element = X690Element::new(
1137                Tag::new(TagClass::UNIVERSAL, UNIV_TAG_INTEGER),
1138                X690Value::Primitive(indirect_ref_bytes.into_inner().into()),
1139            );
1140            inner_elements.push(indirect_ref_element);
1141        }
1142    };
1143    match &value.data_value_descriptor {
1144        Some(dvd) => {
1145            let mut bytes = BytesMut::new().writer();
1146            x690_write_object_descriptor_value(&mut bytes, &dvd)?;
1147            let element = X690Element::new(
1148                Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OBJECT_DESCRIPTOR),
1149                X690Value::Primitive(bytes.into_inner().into()),
1150            );
1151            inner_elements.push(element);
1152        }
1153        None => (),
1154    };
1155    let mut data_value_bytes = BytesMut::new().writer();
1156    match &value.data_value {
1157        ExternalEncoding::single_ASN1_type(t) => {
1158            let el = BER.encode_any(t)?;
1159            x690_write_tlv(&mut data_value_bytes, &el)?
1160        },
1161        ExternalEncoding::octet_aligned(o) => x690_write_octet_string_value(&mut data_value_bytes, o)?,
1162        ExternalEncoding::arbitrary(b) => x690_write_bit_string_value(&mut data_value_bytes, b)?,
1163    };
1164    let data_value_element = X690Element::new(
1165        Tag::new(TagClass::CONTEXT, 1),
1166        X690Value::Primitive(data_value_bytes.into_inner().into()),
1167    );
1168    inner_elements.push(data_value_element);
1169    Ok(inner_elements)
1170}
1171
1172/// Write an `EXTERNAL` value as an X.690-encoded element
1173///
1174/// This function writes an `EXTERNAL` value as an X.690-encoded element.
1175/// It handles the encoding of the identification, data value descriptor,
1176/// and data value.
1177///
1178/// # Arguments
1179/// * `output` - The writable stream to write the `EXTERNAL` value to
1180///
1181/// # Returns
1182/// The number of bytes written to the writable stream
1183///
1184/// NOTE: This has to be encoded in a strange way that is detailed in ITU-T
1185/// Recommendation X.690, Section 8.18.
1186pub fn x690_write_external_value<W>(output: &mut W, value: &EXTERNAL) -> Result<usize>
1187where
1188    W: Write,
1189{
1190    let components = x690_encode_external_components(value)?;
1191    let mut bytes_written: usize = 0;
1192    for component in components {
1193        bytes_written += x690_write_tlv(output, &component)?;
1194    }
1195    Ok(bytes_written)
1196}
1197
1198/// Write a `REAL` value as an X.690-encoded element
1199///
1200/// This function writes a `REAL` value as an X.690-encoded element.
1201/// It handles the encoding of the value according to ITU Recommendation
1202/// X.690, Section 8.5.
1203///
1204/// This adheres to the Basic Encoding Rules (BER) encoding of `REAL` values,
1205/// but not necessarily the Distinguished Encoding Rules (DER) encoding or
1206/// the Canonical Encoding Rules (CER).
1207///
1208/// # Arguments
1209/// * `output` - The writable stream to write the `REAL` value to
1210///
1211/// # Returns
1212/// The number of bytes written to the writable stream
1213///
1214pub fn x690_write_real_value<W>(output: &mut W, value: &REAL) -> Result<usize>
1215where
1216    W: Write,
1217{
1218    // This may seem like a floating precision problem, but this is how the
1219    // `num` crate does it:
1220    // https://github.com/rust-num/num-traits/blob/5397a1c27124af874e42d3d185f78d8ce01ecf69/src/identities.rs#L61
1221    let is_zero = *value == 0.0;
1222    // If the real value is the value plus zero, there shall be no contents octets in the encoding.
1223    if is_zero {
1224        return Ok(0);
1225    }
1226    // If the real value is the value minus zero, then it shall be encoded as specified in 8.5.9.
1227    if is_zero && value.is_sign_negative() {
1228        return output.write(&[X690_REAL_SPECIAL | X690_SPECIAL_REAL_MINUS_ZERO]);
1229    }
1230
1231    if value.is_nan() {
1232        return output.write(&[X690_REAL_SPECIAL | X690_SPECIAL_REAL_NOT_A_NUMBER]);
1233    }
1234
1235    if value.is_infinite() {
1236        if value.is_sign_negative() {
1237            return output.write(&[X690_REAL_SPECIAL | X690_SPECIAL_REAL_MINUS_INFINITY]);
1238        } else {
1239            return output.write(&[X690_REAL_SPECIAL | X690_SPECIAL_REAL_PLUS_INFINITY]);
1240        }
1241    }
1242
1243    let sign_bit: u8 = if value.is_sign_negative() {
1244        X690_REAL_NEGATIVE
1245    } else {
1246        X690_REAL_POSITIVE
1247    };
1248    let base_bits: u8 = X690_REAL_BASE_2;
1249    let scaling_factor: u8 = 0;
1250    let bits = value.to_bits();
1251    let mantissa_mask = (1u64 << 52) - 1;
1252    let mantissa: u64 = bits & mantissa_mask;
1253    let biased_exp = ((bits >> 52) & 0x7FF) as u16;
1254
1255    // For normal numbers, add the implicit leading 1
1256    let mut mantissa = if biased_exp != 0 { mantissa | (1u64 << 52) } else { mantissa };
1257    let mut exponent = if biased_exp != 0 { biased_exp as i16 - 1023 - 52 } else { -1023 - 51 };
1258
1259    // Normalize - remove trailing zeros
1260    while mantissa > 0 && mantissa & 1 == 0 {
1261        mantissa >>= 1;
1262        exponent += 1;
1263    }
1264
1265    let e_bytes = exponent.to_be_bytes();
1266    let mut bytes_written: usize = 0;
1267    if exponent > u8::MAX as i16 {
1268        let byte0: u8 = X690_REAL_BINARY
1269            | sign_bit
1270            | base_bits
1271            | scaling_factor
1272            | X690_REAL_EXPONENT_FORMAT_2_OCTET;
1273        bytes_written += output.write(&[byte0, e_bytes[0], e_bytes[1]])?;
1274    } else {
1275        let byte0: u8 = X690_REAL_BINARY
1276            | sign_bit
1277            | base_bits
1278            | scaling_factor
1279            | X690_REAL_EXPONENT_FORMAT_1_OCTET;
1280        bytes_written += output.write(&[byte0, e_bytes[1]])?;
1281    };
1282
1283    return match x690_write_i64_value(output, mantissa as i64) {
1284        Err(e) => return Err(e),
1285        Ok(wrote) => Ok(wrote + bytes_written),
1286    };
1287}
1288
1289/// Encode the `identification` field of a context-switching type
1290///
1291/// This function encodes the `identification` field of a context-switching type,
1292/// such as an `EXTERNAL` or `EMBEDDED PDV`, as an X.690-encoded element.
1293///
1294/// Returns the X.690-encoded element.
1295///
1296/// # Arguments
1297/// * `id` - The `PresentationContextSwitchingTypeIdentification` value to convert
1298///
1299/// # Returns
1300/// The X.690-encoded element.
1301///
1302pub fn x690_encode_context_switching_identification(
1303    id: &PresentationContextSwitchingTypeIdentification,
1304) -> Result<X690Element> {
1305    match id {
1306        PresentationContextSwitchingTypeIdentification::syntaxes(syntaxes) => {
1307            let mut abstract_value_bytes = BytesMut::new().writer();
1308            let mut transfer_value_bytes = BytesMut::new().writer();
1309            x690_write_object_identifier_value(
1310                &mut abstract_value_bytes,
1311                &syntaxes.r#abstract,
1312            )?;
1313            x690_write_object_identifier_value(&mut transfer_value_bytes, &syntaxes.transfer)?;
1314            let mut syntaxes_elements: Vec<X690Element> = Vec::with_capacity(2);
1315            syntaxes_elements.push(X690Element::new(
1316                Tag::new(TagClass::CONTEXT, 0),
1317                X690Value::Primitive(abstract_value_bytes.into_inner().into()),
1318            ));
1319            syntaxes_elements.push(X690Element::new(
1320                Tag::new(TagClass::CONTEXT, 1),
1321                X690Value::Primitive(transfer_value_bytes.into_inner().into()),
1322            ));
1323            let element = X690Element::new(
1324                Tag::new(TagClass::CONTEXT, 0),
1325                X690Value::Constructed(Arc::new(syntaxes_elements)),
1326            );
1327            return Ok(X690Element::new(
1328                Tag::new(TagClass::CONTEXT, 0),
1329                X690Value::Constructed(Arc::new(Vec::from([ element ]))),
1330            ));
1331        }
1332        PresentationContextSwitchingTypeIdentification::syntax(oid) => {
1333            // We assume that, on average, each OID arc is encoded on two bytes.
1334            let mut bytes = BytesMut::with_capacity(oid.as_x690_slice().len()).writer();
1335            x690_write_object_identifier_value(&mut bytes, &oid)?;
1336            let element = X690Element::new(
1337                Tag::new(TagClass::CONTEXT, 1),
1338                X690Value::Primitive(bytes.into_inner().into()),
1339            );
1340            return Ok(X690Element::new(
1341                Tag::new(TagClass::CONTEXT, 0),
1342                X690Value::Constructed(Arc::new(Vec::from([ element ]))),
1343            ));
1344        }
1345        PresentationContextSwitchingTypeIdentification::presentation_context_id(pci) => {
1346            let mut bytes = BytesMut::with_capacity(pci.len()).writer();
1347            x690_write_integer_value(&mut bytes, pci)?;
1348            let element = X690Element::new(
1349                Tag::new(TagClass::CONTEXT, 2),
1350                X690Value::Primitive(bytes.into_inner().into()),
1351            );
1352            return Ok(X690Element::new(
1353                Tag::new(TagClass::CONTEXT, 0),
1354                X690Value::Constructed(Arc::new(Vec::from([ element ]))),
1355            ));
1356        }
1357        PresentationContextSwitchingTypeIdentification::context_negotiation(cn) => {
1358            let mut pci_bytes = BytesMut::new().writer();
1359            x690_write_integer_value(&mut pci_bytes, &cn.presentation_context_id)?;
1360            let pci_element = X690Element::new(
1361                Tag::new(TagClass::CONTEXT, 0),
1362                X690Value::Primitive(pci_bytes.into_inner().into()),
1363            );
1364            let mut transfer_syntax_bytes = BytesMut::new().writer();
1365            x690_write_object_identifier_value(
1366                &mut transfer_syntax_bytes,
1367                &cn.transfer_syntax,
1368            )?;
1369            let transfer_syntax_element = X690Element::new(
1370                Tag::new(TagClass::CONTEXT, 1),
1371                X690Value::Primitive(transfer_syntax_bytes.into_inner().into()),
1372            );
1373            let cn_elements: Vec<X690Element> = vec![pci_element, transfer_syntax_element];
1374            let element = X690Element::new(
1375                Tag::new(TagClass::CONTEXT, 3),
1376                X690Value::Constructed(Arc::new(cn_elements)),
1377            );
1378            return Ok(X690Element::new(
1379                Tag::new(TagClass::CONTEXT, 0),
1380                X690Value::Constructed(Arc::new(Vec::from([ element ]))),
1381            ));
1382        }
1383        PresentationContextSwitchingTypeIdentification::transfer_syntax(ts) => {
1384            let mut bytes = BytesMut::new().writer();
1385            x690_write_object_identifier_value(&mut bytes, &ts)?;
1386            let element = X690Element::new(
1387                Tag::new(TagClass::CONTEXT, 4),
1388                X690Value::Primitive(bytes.into_inner().into()),
1389            );
1390            return Ok(X690Element::new(
1391                Tag::new(TagClass::CONTEXT, 0),
1392                X690Value::Constructed(Arc::new(Vec::from([ element ]))),
1393            ));
1394        }
1395        PresentationContextSwitchingTypeIdentification::fixed => {
1396            let element = X690Element::new(
1397                Tag::new(TagClass::CONTEXT, 5),
1398                X690Value::Primitive(Bytes::new()),
1399            );
1400            return Ok(X690Element::new(
1401                Tag::new(TagClass::CONTEXT, 0),
1402                X690Value::Constructed(Arc::new(Vec::from([ element ]))),
1403            ));
1404        }
1405    }
1406}
1407
1408/// Encode the components of an `EMBEDDED PDV` value as X.690-encoded elements
1409///
1410/// This function encodes the components of an `EMBEDDED PDV` value as X.690-encoded elements.
1411/// It handles the encoding of the `identification` and `data-value`.
1412///
1413/// # Arguments
1414/// * `value` - The `EMBEDDED PDV` value to encode
1415///
1416/// To be a complete `EMBEDDED PDV` value, these MUST be contained within a "parent" element
1417/// having tag `[UNIVERSAL 11]` and it MUST be constructed.
1418pub fn x690_encode_embedded_pdv_components (value: &EmbeddedPDV) -> Result<Vec<X690Element>> {
1419    let id = x690_encode_context_switching_identification(&value.identification)?;
1420    let mut data_value_bytes = BytesMut::new().writer();
1421    x690_write_octet_string_value(&mut data_value_bytes, &value.data_value)?;
1422    let data_value_element = X690Element::new(
1423        Tag::new(TagClass::CONTEXT, 1),
1424        X690Value::Primitive(data_value_bytes.into_inner().into()),
1425    );
1426    Ok(vec![id, data_value_element])
1427}
1428
1429/// Write an `EMBEDDED PDV` value as an X.690-encoded element
1430///
1431/// This function writes an `EMBEDDED PDV` value as an X.690-encoded element.
1432/// It handles the encoding of the `identification`, data value descriptor,
1433/// and `data-value`.
1434///
1435/// # Arguments
1436/// * `output` - The writable stream to write the `EMBEDDED PDV` value to
1437/// * `value` - The `EMBEDDED PDV` value to write
1438///
1439/// # Returns
1440/// The number of bytes written to the writable stream
1441///
1442pub fn x690_write_embedded_pdv_value<W>(output: &mut W, value: &EmbeddedPDV) -> Result<usize>
1443where
1444    W: Write,
1445{
1446    let components: Vec<X690Element> = x690_encode_embedded_pdv_components(value)?;
1447    let mut bytes_written: usize = 0;
1448    for component in components {
1449        bytes_written += x690_write_tlv(output, &component)?;
1450    }
1451    Ok(bytes_written)
1452}
1453
1454/// Write a `UTF8String` value as an X.690-encoded element, returning the number of bytes written
1455#[inline]
1456pub fn x690_write_utf8_string_value<W>(output: &mut W, value: &str) -> Result<usize>
1457where
1458    W: Write,
1459{
1460    output.write(value.as_bytes())
1461}
1462
1463/// Write a `RELATIVE-OID` value as an X.690-encoded element, returning the number of bytes written
1464#[inline]
1465pub fn x690_write_relative_oid_value<W>(output: &mut W, value: &RELATIVE_OID) -> Result<usize>
1466where
1467    W: Write,
1468{
1469    output.write(value.as_x690_slice())
1470}
1471
1472/// Write a `TIME` value as an X.690-encoded element, returning the number of bytes written
1473#[inline]
1474pub fn x690_write_time_value<W>(output: &mut W, value: &TIME) -> Result<usize>
1475where
1476    W: Write,
1477{
1478    output.write(value.as_bytes())
1479}
1480
1481/// Write a `UTCTime` value as an X.690-encoded element, returning the number of bytes written
1482#[inline]
1483pub fn x690_write_utc_time_value<W>(output: &mut W, value: &UTCTime) -> Result<usize>
1484where
1485    W: Write,
1486{
1487    output.write(value.to_string().as_bytes())
1488}
1489
1490/// Write a `GeneralizedTime` value as an X.690-encoded element, returning the number of bytes written
1491#[inline]
1492pub fn x690_write_generalized_time_value<W>(
1493    output: &mut W,
1494    value: &GeneralizedTime,
1495) -> Result<usize>
1496where
1497    W: Write,
1498{
1499    output.write(value.to_string().as_bytes())
1500}
1501
1502/// Write a `UniversalString` value as an X.690-encoded element, returning the number of bytes written
1503#[inline]
1504pub fn x690_write_universal_string_value<W>(
1505    output: &mut W,
1506    value: &[u32],
1507) -> Result<usize>
1508where
1509    W: Write,
1510{
1511    for c in value {
1512        output.write(&c.to_be_bytes())?;
1513    }
1514    Ok(value.len() * 4)
1515}
1516
1517/// Encode the components of a `CharacterString` value as X.690-encoded elements
1518///
1519/// This function encodes the components of a `CharacterString` value as X.690-encoded elements.
1520/// It handles the encoding of the `identification` and `string-value` fields.
1521///
1522/// # Arguments
1523/// * `value` - The `CharacterString` value to encode
1524///
1525/// # Returns
1526/// A vector of X.690-encoded elements representing the components of the `CharacterString` value
1527///
1528/// To be a complete `CharacterString` value, these MUST be contained within a "parent" element
1529/// having tag `[UNIVERSAL 29]` and it MUST be constructed.
1530pub fn x690_encode_character_string_components (value: &CharacterString) -> Result<Vec<X690Element>> {
1531    let id = x690_encode_context_switching_identification(&value.identification)?;
1532    let mut data_value_bytes = BytesMut::new().writer();
1533    x690_write_octet_string_value(&mut data_value_bytes, &value.string_value)?;
1534    let data_value_element = X690Element::new(
1535        Tag::new(TagClass::CONTEXT, 1),
1536        X690Value::Primitive(data_value_bytes.into_inner().into()),
1537    );
1538    Ok(vec![id, data_value_element])
1539}
1540
1541/// Write a `CharacterString` value as an X.690-encoded element, returning the number of bytes written
1542///
1543/// This function writes a `CharacterString` value as an X.690-encoded element.
1544/// It handles the encoding of the `identification` and `string-value` fields.
1545///
1546/// # Arguments
1547/// * `output` - The writable stream to write the `CharacterString` value to
1548/// * `value` - The `CharacterString` value to write
1549///
1550/// # Returns
1551/// The number of bytes written to the writable stream
1552///
1553pub fn x690_write_character_string_value<W>(
1554    output: &mut W,
1555    value: &CharacterString,
1556) -> Result<usize>
1557where
1558    W: Write,
1559{
1560    let components: Vec<X690Element> = x690_encode_character_string_components(value)?;
1561    let mut bytes_written: usize = 0;
1562    for component in components {
1563        bytes_written += x690_write_tlv(output, &component)?;
1564    }
1565    Ok(bytes_written)
1566}
1567
1568/// Write a `BMPString` value as an X.690-encoded element, returning the number of bytes written
1569pub fn x690_write_bmp_string_value<W>(output: &mut W, value: &[u16]) -> Result<usize>
1570where
1571    W: Write,
1572{
1573    for c in value {
1574        output.write(&c.to_be_bytes())?;
1575    }
1576    Ok(value.len() * 2)
1577}
1578
1579/// Write a string value as an X.690-encoded element, returning the number of bytes written
1580#[inline]
1581pub fn x690_write_string_value<W>(output: &mut W, value: &str) -> Result<usize>
1582where
1583    W: Write,
1584{
1585    output.write(value.as_bytes())
1586}
1587
1588/// Write a `DATE` value as an X.690-encoded element, returning the number of bytes written
1589pub fn x690_write_date_value<W>(output: &mut W, value: &DATE) -> Result<usize>
1590where
1591    W: Write,
1592{
1593    if value.month > 12 || value.month == 0 || value.day > 31 || value.day == 0 {
1594        return Err(Error::from(ErrorKind::InvalidData));
1595    }
1596    output.write(value.to_num_string().as_bytes())
1597}
1598
1599/// Write a `TIME-OF-DAY` value as an X.690-encoded element, returning the number of bytes written
1600pub fn x690_write_time_of_day_value<W>(output: &mut W, value: &TIME_OF_DAY) -> Result<usize>
1601where
1602    W: Write,
1603{
1604    if value.hour > 23 || value.minute > 59 || value.second > 59 {
1605        return Err(Error::from(ErrorKind::InvalidData));
1606    }
1607    output.write(value.to_num_string().as_bytes())
1608}
1609
1610/// Write a `DATE-TIME` value as an X.690-encoded element, returning the number of bytes written
1611pub fn x690_write_date_time_value<W>(output: &mut W, value: &DATE_TIME) -> Result<usize>
1612where
1613    W: Write,
1614{
1615    output.write(value.to_num_string().as_bytes())
1616}
1617
1618/// Write a `DURATION` value as an X.690-encoded element, returning the number of bytes written
1619pub fn x690_write_duration_value<W>(output: &mut W, value: &DURATION_EQUIVALENT) -> Result<usize>
1620where
1621    W: Write,
1622{
1623    output.write(&value.to_string().as_bytes()[1..]) // Skip the "P"
1624}
1625
1626/// Write an X.690-encoded value to a writable stream, returning the number of bytes written
1627fn x690_write_value<W>(output: &mut W, encoding: &X690Value) -> Result<usize>
1628where
1629    W: Write,
1630{
1631    match encoding {
1632        X690Value::Primitive(v) => output.write(&v),
1633        X690Value::Constructed(components) => {
1634            let mut sum: usize = 0;
1635            for component in components.iter() {
1636                sum += x690_write_tlv(output, component)?;
1637            }
1638            Ok(sum)
1639        },
1640        X690Value::Serialized(v) => {
1641            let (_, el) = BER.decode_from_slice(&v)?;
1642            x690_write_value(output, &el.value)
1643        }
1644    }
1645}
1646
1647/// Write an X.690-encoded element to a writable stream, returning the number of bytes written
1648pub fn x690_write_tlv<W>(output: &mut W, node: &X690Element) -> Result<usize>
1649where
1650    W: Write,
1651{
1652    if let X690Value::Serialized(serialized) = &node.value {
1653        return output.write(&serialized);
1654    }
1655    let mut bytes_written: usize = 0;
1656    bytes_written += x690_write_tag(output, node.tag.tag_class, node.is_constructed(), node.tag.tag_number)?;
1657    bytes_written += x690_write_length(output, node.value.len())?;
1658    bytes_written += x690_write_value(output, &node.value)?;
1659    Ok(bytes_written)
1660}
1661
1662/// Deconstruct an X.690-encoded element that could be primitively-constructed
1663///
1664/// The X.690 encoding rules allow for some universal types to be either
1665/// primitively-constructed or constructed. However, for the purposes of
1666/// validation or decoding, we may want to "deconstruct" such constructed
1667/// values to a single primitive value.
1668///
1669/// One such example is the `GeneralizedTime`. While it may be constructed,
1670/// it might be difficult to implement parsing and validation when it is
1671/// split across multiple X.690 tag-length-value (TLV) elements.
1672///
1673/// If the element is already primitively constructed, this just returns a
1674/// reference to it, so no copying overhead is incurred.
1675/// 
1676/// If you can, prefer to use `iter_deconstruction` instead: even if the
1677/// element is constructed, your use case might not require a view of the
1678/// entire deconstruction at one time. For example, when validating a
1679/// `NumericString`, you can just validate each chunk individually, rather
1680/// than joining them into a single string. This should be much faster.
1681pub fn deconstruct<'a>(el: &'a X690Element) -> ASN1Result<Cow<'a, [u8]>> {
1682    match &el.value {
1683        X690Value::Primitive(bytes) => Ok(Cow::Borrowed(bytes)),
1684        X690Value::Constructed(children) => {
1685            let mut deconstructed_value = BytesMut::new();
1686            for child in children.iter() {
1687                /* Just to be clear, this is 100% intentional. In ITU X.690, it says that the substrings of a string
1688                type are to have OCTET STRING tags and it even has examples where it confirms this visually. */
1689                if child.tag.tag_class != TagClass::UNIVERSAL
1690                    || child.tag.tag_number != UNIV_TAG_OCTET_STRING
1691                {
1692                    let mut err =
1693                        ASN1Error::new(ASN1ErrorCode::string_constructed_with_invalid_tagging);
1694                    err.tag = Some(Tag::new(el.tag.tag_class, el.tag.tag_number));
1695                    err.length = Some(el.len());
1696                    err.constructed = Some(true);
1697                    return Err(err);
1698                }
1699                let deconstructed_child = deconstruct(&child)?;
1700                deconstructed_value.put(deconstructed_child.as_ref());
1701            }
1702            Ok(Cow::Owned(Vec::<u8>::from(deconstructed_value)))
1703        },
1704        X690Value::Serialized(v) => {
1705            let (_, el) = BER.decode_from_slice(&v)?;
1706            Ok(Cow::Owned(deconstruct(&el)?.into_owned()))
1707        }
1708    }
1709}
1710
1711/// An iterator that iterates over the primitive content octets of
1712/// the constituent elements of this element, recursively.
1713/// 
1714/// In other words a `UTF8String` encoding that is structed like so:
1715/// 
1716/// ```text
1717/// [UNIV 12]
1718///     [UNIV 4] "hello"
1719///     [UNIV 4]
1720///         [UNIV 4] " "
1721///     [UNIV 4] "world"
1722/// ```
1723/// 
1724/// Will result in the content octets for "hello", " ", and "world" being
1725/// returned from the iterator, in that order.
1726/// 
1727pub struct DeconstructionIterator<'a> {
1728    el: &'a X690Element,
1729    i: usize,
1730    child: Option<Box<DeconstructionIterator<'a>>>,
1731    recursion_limit: usize,
1732    recursion_depth: usize,
1733}
1734
1735impl <'a> DeconstructionIterator<'a> {
1736
1737    /// Create a new iterator
1738    pub fn new(el: &'a X690Element) -> DeconstructionIterator<'a> {
1739        DeconstructionIterator {
1740            el, i: 0,
1741            child: None,
1742            recursion_limit: 5,
1743            recursion_depth: 0,
1744        }
1745    }
1746}
1747
1748impl <'a> Iterator for DeconstructionIterator<'a> {
1749    type Item = ASN1Result<Cow<'a, [u8]>>;
1750
1751    fn next(&mut self) -> Option<Self::Item> {
1752        if self.recursion_depth > self.recursion_limit {
1753            return None;
1754        }
1755        if let Some(child) = self.child.as_mut() {
1756            if let Some(next) = child.next() {
1757                return Some(next);
1758            }
1759        }
1760        match &self.el.value {
1761            X690Value::Primitive(bytes) => {
1762                if self.i > 0 {
1763                    return None;
1764                }
1765                self.i += 1;
1766                Some(Ok(Cow::Borrowed(bytes.as_ref())))
1767            },
1768            X690Value::Constructed(children) => {
1769                // Use a while loop because we do not want to stop if one
1770                // constructed child element has no children.
1771                while let Some(child) = children.get(self.i) {
1772                    if child.tag.tag_class != TagClass::UNIVERSAL
1773                        || child.tag.tag_number != UNIV_TAG_OCTET_STRING
1774                    {
1775                        let mut err =
1776                            ASN1Error::new(ASN1ErrorCode::string_constructed_with_invalid_tagging);
1777                        err.tag = Some(Tag::new(child.tag.tag_class, child.tag.tag_number));
1778                        err.length = Some(child.len());
1779                        err.constructed = Some(true);
1780                        return Some(Err(err));
1781                    }
1782                    self.i = self.i.saturating_add(1);
1783                    let mut new_iter = DeconstructionIterator{
1784                        el: child,
1785                        i: 0,
1786                        child: None,
1787                        recursion_limit: self.recursion_limit,
1788                        recursion_depth: self.recursion_depth.saturating_add(1),
1789                    };
1790                    let maybe_grandchild = new_iter.next();
1791                    if let Some(grandchild) = maybe_grandchild {
1792                        self.child = Some(Box::new(new_iter));
1793                        return Some(grandchild);
1794                    }
1795                }
1796                self.recursion_depth = usize::MAX;
1797                None
1798            },
1799            X690Value::Serialized(v) => {
1800                if self.i > 0 {
1801                    return None;
1802                }
1803                let (_, el) = match BER.decode_from_slice(&v) {
1804                    Ok(x) => x,
1805                    Err(e) => return Some(Err(e)),
1806                };
1807                self.i += 1;
1808                let decon = match deconstruct(&el) {
1809                    Ok(x) => x,
1810                    Err(e) => return Some(Err(e)),
1811                };
1812                Some(Ok(Cow::Owned(decon.into_owned())))
1813            },
1814        }
1815    }
1816
1817}
1818
1819/// Read a `BOOLEAN` value from an X.690-encoded element's content octets
1820pub const fn x690_read_boolean_value(value_bytes: ByteSlice) -> ASN1Result<BOOLEAN> {
1821    if value_bytes.len() != 1 {
1822        let err = ASN1Error::new(ASN1ErrorCode::x690_boolean_not_one_byte);
1823        return Err(err);
1824    }
1825    Ok(value_bytes[0] > 0)
1826}
1827
1828/// Read an `INTEGER` value from an X.690-encoded element's content octets
1829#[inline]
1830pub fn x690_read_integer_value(value_bytes: ByteSlice) -> ASN1Result<INTEGER> {
1831    // Intentionally not validating this. Most integers are small and correct.
1832    // If they have padding, its obvious how to handle that.
1833    Ok(Vec::from(value_bytes))
1834}
1835
1836/// Read an `i64` value from an X.690-encoded element's content octets
1837#[inline]
1838pub fn x690_read_i64_value(value_bytes: ByteSlice) -> ASN1Result<i64> {
1839    match read_i64(value_bytes) {
1840        Some(v) => Ok(v),
1841        None => Err(ASN1Error::new(ASN1ErrorCode::value_too_big)),
1842    }
1843}
1844
1845/// Read an `ENUMERATED` value from an X.690-encoded element's content octets
1846#[inline]
1847pub fn x690_read_enum_value(value_bytes: ByteSlice) -> ASN1Result<ENUMERATED> {
1848    x690_read_i64_value(value_bytes)
1849}
1850
1851/// Read an `OBJECT IDENTIFIER` value from an X.690-encoded element's content octets
1852#[inline]
1853pub fn x690_read_object_identifier_value(value_bytes: ByteSlice) -> ASN1Result<OBJECT_IDENTIFIER> {
1854    OBJECT_IDENTIFIER::from_x690_encoding_slice(value_bytes)
1855}
1856
1857/// Read a `RELATIVE-OID` value from an X.690-encoded element's content octets
1858#[inline]
1859pub fn x690_read_relative_oid_value(value_bytes: ByteSlice) -> ASN1Result<RELATIVE_OID> {
1860    RELATIVE_OID::from_x690_encoding_slice(value_bytes)
1861}
1862
1863/// Read a `DATE` value from an X.690-encoded element's content octets
1864#[inline]
1865pub fn x690_read_date_value(value_bytes: ByteSlice) -> ASN1Result<DATE> {
1866    DATE::try_from(value_bytes)
1867}
1868
1869/// Read a `TIME-OF-DAY` value from an X.690-encoded element's content octets
1870#[inline]
1871pub fn x690_read_time_of_day_value(value_bytes: ByteSlice) -> ASN1Result<TIME_OF_DAY> {
1872    TIME_OF_DAY::try_from(value_bytes)
1873}
1874
1875/// Read a `DATE-TIME` value from an X.690-encoded element's content octets
1876#[inline]
1877pub fn x690_read_date_time_value(value_bytes: ByteSlice) -> ASN1Result<DATE_TIME> {
1878    DATE_TIME::try_from(value_bytes)
1879}
1880
1881/// Read a `DURATION` value from an X.690-encoded element's content octets
1882#[inline]
1883pub fn x690_read_duration_value(value_bytes: ByteSlice) -> ASN1Result<DURATION> {
1884    DURATION::try_from(value_bytes)
1885}
1886
1887/// A trait for relating an X.690-encoded element to something
1888pub trait RelateTLV {
1889
1890    /// Relate something to an X.690-encoded tag-length-value (TLV) element
1891    fn relate_tlv (&mut self, el: &X690Element);
1892}
1893
1894impl RelateTLV for ASN1Error {
1895    fn relate_tlv (&mut self, el: &X690Element) {
1896        self.tag = Some(el.tag);
1897        self.constructed = Some(el.is_constructed());
1898        self.length = Some(el.len());
1899    }
1900}
1901
1902/// The Root Component Type List (RCTL) #1 for the X.690-specific encoding of
1903/// an `EXTERNAL` value as described in ITU Recommendation X.690, Section 8.18.
1904///
1905/// For reference, the full ASN.1 for this is:
1906///
1907/// ```asn1
1908/// [UNIVERSAL 8] IMPLICIT SEQUENCE {
1909///     direct-reference        OBJECT IDENTIFIER OPTIONAL,
1910///     indirect-reference      INTEGER OPTIONAL,
1911///     data-value-descriptor   ObjectDescriptor OPTIONAL,
1912///     encoding CHOICE {
1913///         single-ASN1-type    [0] ABSTRACT-SYNTAX.&Type,
1914///         octet-aligned       [1] IMPLICIT OCTET STRING,
1915///         arbitrary           [2] IMPLICIT BIT STRING } }
1916/// ```
1917pub const _RCTL1_FOR_EXTERNAL: &[ComponentSpec; 4] = &[
1918    ComponentSpec::new(
1919        "direct-reference",
1920        true,
1921        TagSelector::tag((
1922            TagClass::UNIVERSAL,
1923            UNIV_TAG_OBJECT_IDENTIFIER,
1924        )),
1925        None,
1926        None,
1927    ),
1928    ComponentSpec::new(
1929        "indirect-reference",
1930        true,
1931        TagSelector::tag((TagClass::UNIVERSAL, UNIV_TAG_INTEGER)),
1932        None,
1933        None,
1934    ),
1935    ComponentSpec::new(
1936        "data-value-descriptor",
1937        true,
1938        TagSelector::tag((
1939            TagClass::UNIVERSAL,
1940            UNIV_TAG_OBJECT_DESCRIPTOR,
1941        )),
1942        None,
1943        None,
1944    ),
1945    ComponentSpec::new(
1946        "encoding",
1947        false,
1948        TagSelector::or(&[
1949            &TagSelector::tag((TagClass::CONTEXT, 0)),
1950            &TagSelector::tag((TagClass::CONTEXT, 1)),
1951            &TagSelector::tag((TagClass::CONTEXT, 2)),
1952        ]),
1953        None,
1954        None,
1955    ),
1956];
1957
1958/// The Extended Attribute List (EAL) for the X.690-specific encoding of
1959/// an `EXTERNAL` value as described in ITU Recommendation X.690, Section 8.18.
1960/// It is empty, so this is basically just a formality.
1961pub const _EAL_FOR_EXTERNAL: &[ComponentSpec; 0] = &[];
1962
1963/// The Root Component Type List (RCTL) #2 for the X.690-specific encoding of
1964/// an `EXTERNAL` value as described in ITU Recommendation X.690, Section 8.18.
1965/// It is empty, so this is basically just a formality.
1966pub const _RCTL2_FOR_EXTERNAL: &[ComponentSpec; 0] = &[];
1967
1968#[cfg(test)]
1969mod tests {
1970
1971    use super::*;
1972    use std::sync::Arc;
1973    use wildboar_asn1::{
1974        Tag, TagClass, UNIV_TAG_BOOLEAN, UNIV_TAG_IA5_STRING, UNIV_TAG_OCTET_STRING, UNIV_TAG_SEQUENCE
1975    };
1976    use bytes::Bytes;
1977
1978    #[test]
1979    fn test_x690_write_boolean_value() {
1980        let mut output = BytesMut::new().writer();
1981        crate::x690_write_boolean_value(&mut output, &true).unwrap();
1982        crate::x690_write_boolean_value(&mut output, &false).unwrap();
1983        let output: Bytes = output.into_inner().into();
1984        assert_eq!(output.len(), 2);
1985        assert!(output.starts_with(&[0xFF, 0x00]));
1986    }
1987
1988    #[test]
1989    fn test_x690_write_integer_value() {
1990        let mut output = BytesMut::new();
1991        let mut i = 0;
1992        for value in -128i8..127i8 {
1993            let mut out = output.writer();
1994            crate::x690_write_enum_value(&mut out, &i64::from(value)).unwrap();
1995            output = out.into_inner();
1996            assert_eq!(output[i] as i8, value);
1997            i += 1;
1998        }
1999        assert_eq!(output.len(), 255);
2000    }
2001
2002    #[test]
2003    fn test_x690_write_octet_string_value() {
2004        let mut output = BytesMut::new().writer();
2005        let bytes: Vec<u8> = vec![1, 3, 5, 7, 9];
2006        crate::x690_write_octet_string_value(&mut output, &bytes).unwrap();
2007        let output: Bytes = output.into_inner().into();
2008        assert_eq!(output.len(), 5);
2009        assert!(output.starts_with(&[1, 3, 5, 7, 9]));
2010    }
2011
2012    #[test]
2013    fn test_x690_write_object_identifier_value() {
2014        let mut output = BytesMut::new().writer();
2015        let oid = wildboar_asn1::OBJECT_IDENTIFIER::try_from(vec![2u32, 5, 4, 3]).unwrap();
2016        crate::x690_write_object_identifier_value(&mut output, &oid).unwrap();
2017        let output: Bytes = output.into_inner().into();
2018        assert_eq!(output.len(), 3);
2019        assert!(output.starts_with(&[0x55, 0x04, 0x03]));
2020    }
2021
2022    #[test]
2023    fn test_x690_write_object_descriptor_value() {
2024        let mut output = BytesMut::new().writer();
2025        let value = String::from("commonName");
2026        crate::x690_write_object_descriptor_value(&mut output, &value).unwrap();
2027        let output: Bytes = output.into_inner().into();
2028        assert_eq!(output.len(), value.len());
2029        assert_eq!(
2030            String::from_utf8(output.into()).unwrap(),
2031            String::from("commonName")
2032        );
2033    }
2034
2035    #[test]
2036    fn test_x690_write_real_value() {
2037        let output = BytesMut::new();
2038        let value = 1.2345;
2039        crate::x690_write_real_value(&mut output.writer(), &value).unwrap();
2040    }
2041
2042    #[test]
2043    fn test_constructed_encoding() {
2044        let asn1_data = X690Element::new(
2045            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_SEQUENCE),
2046            crate::X690Value::Constructed(Arc::new(vec![
2047                X690Element::new(
2048                    Tag::new(TagClass::UNIVERSAL, UNIV_TAG_BOOLEAN),
2049                    crate::X690Value::Primitive(Bytes::copy_from_slice(&[ 0xFF ])),
2050                ),
2051                X690Element::new(
2052                    Tag::new(TagClass::UNIVERSAL, UNIV_TAG_INTEGER),
2053                    crate::X690Value::Primitive(Bytes::copy_from_slice(&[ 0x01, 0x03 ])),
2054                ),
2055            ])),
2056        );
2057        let mut output = Vec::new();
2058        match x690_write_tlv(&mut output, &asn1_data) {
2059            Ok(bytes_written) => {
2060                assert_eq!(bytes_written, 9);
2061            }
2062            Err(e) => panic!("{}", e),
2063        }
2064        assert!(output.starts_with(&[
2065            X690_TAG_CLASS_UNIVERSAL
2066            | 0b0010_0000 // Constructed
2067            | UNIV_TAG_SEQUENCE as u8,
2068            0x07,
2069            0x01,
2070            0x01,
2071            0xFF,
2072            0x02,
2073            0x02,
2074            0x01,
2075            0x03,
2076        ]));
2077    }
2078
2079    #[test]
2080    fn test_ber_decode_definite_short() {
2081        let encoded_data: Vec<u8> = vec![
2082            X690_TAG_CLASS_UNIVERSAL
2083            | 0b0010_0000 // Constructed
2084            | UNIV_TAG_SEQUENCE as u8,
2085            0x06,
2086            0x01,
2087            0x01,
2088            0xFF,
2089            0x02,
2090            0x01,
2091            0x7F,
2092        ];
2093        match BER.decode_from_slice(encoded_data.as_slice()) {
2094            Ok((bytes_read, el)) => {
2095                assert_eq!(bytes_read, 8);
2096                assert_eq!(el.tag.tag_class, TagClass::UNIVERSAL);
2097                assert_eq!(el.tag.tag_number, UNIV_TAG_SEQUENCE);
2098                if let X690Value::Constructed(children) = el.value {
2099                    assert_eq!(children.len(), 2);
2100                    assert_eq!(children[0].tag.tag_class, TagClass::UNIVERSAL);
2101                    assert_eq!(children[1].tag.tag_class, TagClass::UNIVERSAL);
2102                    assert_eq!(children[0].tag.tag_number, UNIV_TAG_BOOLEAN);
2103                    assert_eq!(children[1].tag.tag_number, UNIV_TAG_INTEGER);
2104                } else {
2105                    panic!("Decoded non-constructed.");
2106                }
2107            }
2108            Err(e) => panic!("{}", e),
2109        };
2110    }
2111
2112    #[test]
2113    fn test_ber_decode_indefinite() {
2114        let encoded_data: Vec<u8> = vec![
2115            X690_TAG_CLASS_UNIVERSAL
2116            | 0b0010_0000 // Constructed
2117            | UNIV_TAG_SEQUENCE as u8,
2118            0x80, // Indefinite length
2119            0x01,
2120            0x01,
2121            0xFF,
2122            0x02,
2123            0x01,
2124            0x7F,
2125            0x00, // End of content
2126            0x00,
2127        ];
2128        match BER.decode_from_slice(encoded_data.as_slice()) {
2129            Ok((bytes_read, el)) => {
2130                assert_eq!(bytes_read, 10);
2131                assert_eq!(el.tag.tag_class, TagClass::UNIVERSAL);
2132                assert_eq!(el.tag.tag_number, UNIV_TAG_SEQUENCE);
2133                if let X690Value::Constructed(children) = el.value {
2134                    assert_eq!(children.len(), 2);
2135                    assert_eq!(children[0].tag.tag_class, TagClass::UNIVERSAL);
2136                    assert_eq!(children[1].tag.tag_class, TagClass::UNIVERSAL);
2137                    assert_eq!(children[0].tag.tag_number, UNIV_TAG_BOOLEAN);
2138                    assert_eq!(children[1].tag.tag_number, UNIV_TAG_INTEGER);
2139                } else {
2140                    panic!("Decoded non-constructed.");
2141                }
2142            }
2143            Err(e) => panic!("{}", e),
2144        };
2145    }
2146
2147    #[test]
2148    fn test_deconstruct_primitive() {
2149        // Test deconstructing a primitive value
2150        let bytes = Bytes::copy_from_slice(&[0x01, 0x02, 0x03, 0x04]);
2151        let element = X690Element::new(
2152            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2153            X690Value::Primitive(bytes.clone()),
2154        );
2155
2156        let result = deconstruct(&element).unwrap();
2157        assert_eq!(result.as_ref(), &[0x01, 0x02, 0x03, 0x04]);
2158        // Should be borrowed since it's a primitive
2159        assert!(matches!(result, Cow::Borrowed(_)));
2160    }
2161
2162    #[test]
2163    fn test_deconstruct_constructed_valid() {
2164        // Test deconstructing a constructed value with valid OCTET STRING children
2165        let child1 = X690Element::new(
2166            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2167            X690Value::Primitive(Bytes::copy_from_slice(&[0x01, 0x02])),
2168        );
2169        let child2 = X690Element::new(
2170            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2171            X690Value::Primitive(Bytes::copy_from_slice(&[0x03, 0x04])),
2172        );
2173
2174        let element = X690Element::new(
2175            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2176            X690Value::Constructed(Arc::new(vec![child1, child2])),
2177        );
2178
2179        let result = deconstruct(&element).unwrap();
2180        assert_eq!(result.as_ref(), &[0x01, 0x02, 0x03, 0x04]);
2181        // Should be owned since it's constructed
2182        assert!(matches!(result, Cow::Owned(_)));
2183    }
2184
2185    #[test]
2186    fn test_deconstruct_constructed_invalid_tag_class() {
2187        // Test deconstructing a constructed value with invalid tag class
2188        let child = X690Element::new(
2189            Tag::new(TagClass::APPLICATION, UNIV_TAG_OCTET_STRING), // Wrong tag class
2190            X690Value::Primitive(Bytes::copy_from_slice(&[0x01, 0x02])),
2191        );
2192
2193        let element = X690Element::new(
2194            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2195            X690Value::Constructed(Arc::new(vec![child])),
2196        );
2197
2198        let result = deconstruct(&element);
2199        assert!(result.is_err());
2200        let err = result.unwrap_err();
2201        assert_eq!(err.error_code, ASN1ErrorCode::string_constructed_with_invalid_tagging);
2202    }
2203
2204    #[test]
2205    fn test_deconstruct_constructed_invalid_tag_number() {
2206        // Test deconstructing a constructed value with invalid tag number
2207        let child = X690Element::new(
2208            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_INTEGER), // Wrong tag number
2209            X690Value::Primitive(Bytes::copy_from_slice(&[0x01, 0x02])),
2210        );
2211
2212        let element = X690Element::new(
2213            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2214            X690Value::Constructed(Arc::new(vec![child])),
2215        );
2216
2217        let result = deconstruct(&element);
2218        assert!(result.is_err());
2219        let err = result.unwrap_err();
2220        assert_eq!(err.error_code, ASN1ErrorCode::string_constructed_with_invalid_tagging);
2221    }
2222
2223    #[test]
2224    fn test_deconstruct_constructed_nested() {
2225        // Test deconstructing a constructed value with nested constructed children
2226        let grandchild1 = X690Element::new(
2227            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2228            X690Value::Primitive(Bytes::copy_from_slice(&[0x01, 0x02])),
2229        );
2230        let grandchild2 = X690Element::new(
2231            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2232            X690Value::Primitive(Bytes::copy_from_slice(&[0x03, 0x04])),
2233        );
2234
2235        let child = X690Element::new(
2236            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2237            X690Value::Constructed(Arc::new(vec![grandchild1, grandchild2])),
2238        );
2239
2240        let element = X690Element::new(
2241            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2242            X690Value::Constructed(Arc::new(vec![child])),
2243        );
2244
2245        let result = deconstruct(&element).unwrap();
2246        assert_eq!(result.as_ref(), &[0x01, 0x02, 0x03, 0x04]);
2247    }
2248
2249    #[test]
2250    fn test_deconstruct_constructed_empty() {
2251        // Test deconstructing a constructed value with no children
2252        let element = X690Element::new(
2253            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2254            X690Value::Constructed(Arc::new(vec![])),
2255        );
2256
2257        let result = deconstruct(&element).unwrap();
2258        let empty: [u8; 0] = [];
2259        assert_eq!(result.as_ref(), &empty);
2260    }
2261
2262    #[test]
2263    fn test_deconstruct_serialized() {
2264        // Test deconstructing a serialized value
2265        let inner_bytes = Bytes::copy_from_slice(&[0x01, 0x02, 0x03, 0x04]);
2266        let inner_element = X690Element::new(
2267            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2268            X690Value::Primitive(inner_bytes),
2269        );
2270
2271        // Create a serialized version by encoding the inner element
2272        let mut serialized = Vec::new();
2273        x690_write_tlv(&mut serialized, &inner_element).unwrap();
2274
2275        let element = X690Element::new(
2276            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2277            X690Value::Serialized(Bytes::copy_from_slice(&serialized)),
2278        );
2279
2280        let result = deconstruct(&element).unwrap();
2281        assert_eq!(result.as_ref(), &[0x01, 0x02, 0x03, 0x04]);
2282        // Should be owned since it's serialized
2283        assert!(matches!(result, Cow::Owned(_)));
2284    }
2285
2286    #[test]
2287    fn test_deconstruct_serialized_constructed() {
2288        // Test deconstructing a serialized constructed value
2289        let child1 = X690Element::new(
2290            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2291            X690Value::Primitive(Bytes::copy_from_slice(&[0x01, 0x02])),
2292        );
2293        let child2 = X690Element::new(
2294            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2295            X690Value::Primitive(Bytes::copy_from_slice(&[0x03, 0x04])),
2296        );
2297
2298        let inner_element = X690Element::new(
2299            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2300            X690Value::Constructed(Arc::new(vec![child1, child2])),
2301        );
2302
2303        // Create a serialized version by encoding the inner element
2304        let mut serialized = Vec::new();
2305        x690_write_tlv(&mut serialized, &inner_element).unwrap();
2306
2307        let element = X690Element::new(
2308            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2309            X690Value::Serialized(Bytes::copy_from_slice(&serialized)),
2310        );
2311
2312        let result = deconstruct(&element).unwrap();
2313        assert_eq!(result.as_ref(), &[0x01, 0x02, 0x03, 0x04]);
2314    }
2315
2316    #[test]
2317    fn test_deconstruct_mixed_constructed() {
2318        // Test deconstructing a constructed value with mixed primitive and constructed children
2319        let primitive_child = X690Element::new(
2320            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2321            X690Value::Primitive(Bytes::copy_from_slice(&[0x01, 0x02])),
2322        );
2323
2324        let grandchild1 = X690Element::new(
2325            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2326            X690Value::Primitive(Bytes::copy_from_slice(&[0x03, 0x04])),
2327        );
2328        let grandchild2 = X690Element::new(
2329            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2330            X690Value::Primitive(Bytes::copy_from_slice(&[0x05, 0x06])),
2331        );
2332
2333        let constructed_child = X690Element::new(
2334            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2335            X690Value::Constructed(Arc::new(vec![grandchild1, grandchild2])),
2336        );
2337
2338        let element = X690Element::new(
2339            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2340            X690Value::Constructed(Arc::new(vec![primitive_child, constructed_child])),
2341        );
2342
2343        let result = deconstruct(&element).unwrap();
2344        assert_eq!(result.as_ref(), &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
2345    }
2346
2347    #[test]
2348    fn test_deconstruct_large_data() {
2349        // Test deconstructing with larger data to ensure performance
2350        let mut children = Vec::new();
2351        let mut expected = Vec::new();
2352
2353        for i in 0..100 {
2354            let data = vec![i as u8, (i + 1) as u8, (i + 2) as u8];
2355            expected.extend_from_slice(&data);
2356
2357            let child = X690Element::new(
2358                Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2359                X690Value::Primitive(Bytes::copy_from_slice(&data)),
2360            );
2361            children.push(child);
2362        }
2363
2364        let element = X690Element::new(
2365            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2366            X690Value::Constructed(Arc::new(children)),
2367        );
2368
2369        let result = deconstruct(&element).unwrap();
2370        assert_eq!(result.as_ref(), &expected);
2371    }
2372
2373    #[test]
2374    fn test_deconstruct_serialized_invalid_data() {
2375        // Test deconstructing a serialized value with invalid data
2376        let element = X690Element::new(
2377            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2378            X690Value::Serialized(Bytes::copy_from_slice(&[0x01, 0x02, 0x03])), // Invalid BER
2379        );
2380
2381        let result = deconstruct(&element);
2382        assert!(result.is_err());
2383    }
2384
2385    #[test]
2386    fn test_element_equality_1() {
2387        let element1 = X690Element::new(
2388            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2389            X690Value::Primitive(Bytes::copy_from_slice(&[0x01, 0x02])),
2390        );
2391        let element2 = X690Element::new(
2392            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2393            X690Value::Primitive(Bytes::copy_from_slice(&[0x01, 0x02])),
2394        );
2395        assert_eq!(element1, element2);
2396    }
2397
2398    #[test]
2399    fn test_deconstruct_iter_mixed_constructed() {
2400        // Test deconstructing a constructed value with mixed primitive and constructed children
2401        let primitive_child = X690Element::new(
2402            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2403            X690Value::Primitive(Bytes::copy_from_slice(&[0x01, 0x02])),
2404        );
2405
2406        let grandchild1 = X690Element::new(
2407            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2408            X690Value::Primitive(Bytes::copy_from_slice(&[0x03, 0x04])),
2409        );
2410        let grandchild2 = X690Element::new(
2411            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2412            X690Value::Primitive(Bytes::copy_from_slice(&[0x05, 0x06])),
2413        );
2414
2415        let constructed_child = X690Element::new(
2416            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2417            X690Value::Constructed(Arc::new(vec![grandchild1, grandchild2])),
2418        );
2419
2420        let element = X690Element::new(
2421            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_IA5_STRING),
2422            X690Value::Constructed(Arc::new(vec![primitive_child, constructed_child])),
2423        );
2424
2425        let chunks: ASN1Result<Vec<Cow<[u8]>>> = element.iter_deconstruction().collect();
2426        let chunks = chunks.unwrap();
2427        assert_eq!(chunks.len(), 3);
2428        assert_eq!(chunks[0].as_ref(), &[0x01, 0x02]);
2429        assert_eq!(chunks[1].as_ref(), &[0x03, 0x04]);
2430        assert_eq!(chunks[2].as_ref(), &[0x05, 0x06]);
2431    }
2432
2433    #[test]
2434    fn test_deconstruct_iter_empty_child() {
2435        // Test deconstructing a constructed value with mixed primitive and constructed children
2436        let primitive_child = X690Element::new(
2437            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2438            X690Value::Primitive(Bytes::copy_from_slice(&[0x01, 0x02])),
2439        );
2440
2441        let grandchild1 = X690Element::new(
2442            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2443            X690Value::Constructed(Arc::new(vec![])),
2444        );
2445        let grandchild2 = X690Element::new(
2446            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2447            X690Value::Primitive(Bytes::copy_from_slice(&[0x05, 0x06])),
2448        );
2449
2450        let constructed_child = X690Element::new(
2451            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_OCTET_STRING),
2452            X690Value::Constructed(Arc::new(vec![grandchild1, grandchild2])),
2453        );
2454
2455        let element = X690Element::new(
2456            Tag::new(TagClass::UNIVERSAL, UNIV_TAG_IA5_STRING),
2457            X690Value::Constructed(Arc::new(vec![primitive_child, constructed_child])),
2458        );
2459
2460        let chunks: ASN1Result<Vec<Cow<[u8]>>> = element.iter_deconstruction().collect();
2461        let chunks = chunks.unwrap();
2462        assert_eq!(chunks.len(), 2);
2463        assert_eq!(chunks[0].as_ref(), &[0x01, 0x02]);
2464        assert_eq!(chunks[1].as_ref(), &[0x05, 0x06]);
2465    }
2466
2467}