1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use super::{AsnType, Class, Constraints, ObjectIdentifier, Tag};
use crate::types::fields::{Field, FieldPresence, Fields};

/// An instance of a defined object class.
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub struct InstanceOf<T> {
    /// The OID identifying T's real type.
    pub type_id: ObjectIdentifier,
    /// The value identified by `type_id`.
    pub value: T,
}

impl<T> AsnType for InstanceOf<T> {
    const TAG: Tag = Tag::EXTERNAL;
}

impl<T: crate::Decode> crate::Decode for InstanceOf<T> {
    fn decode_with_tag_and_constraints<D: crate::Decoder>(
        decoder: &mut D,
        tag: Tag,
        _: Constraints,
    ) -> Result<Self, D::Error> {
        decoder.decode_sequence(tag, |sequence| {
            let type_id = ObjectIdentifier::decode(sequence)?;
            let value = sequence.decode_explicit_prefix(Tag::new(Class::Context, 0))?;

            Ok(Self { type_id, value })
        })
    }
}

impl<T: crate::Encode> crate::Encode for InstanceOf<T> {
    fn encode_with_tag_and_constraints<EN: crate::Encoder>(
        &self,
        encoder: &mut EN,
        tag: Tag,
        _: Constraints,
    ) -> core::result::Result<(), EN::Error> {
        encoder.encode_sequence::<Self, _>(tag, |sequence| {
            self.type_id.encode(sequence)?;
            sequence.encode_explicit_prefix(Tag::new(Class::Context, 0), &self.value)?;
            Ok(())
        })?;

        Ok(())
    }
}

impl<T: AsnType> crate::types::Constructed for InstanceOf<T> {
    const FIELDS: Fields = Fields::from_static(&[
        Field {
            tag: ObjectIdentifier::TAG,
            tag_tree: ObjectIdentifier::TAG_TREE,
            presence: FieldPresence::Required,
            name: "type_id",
        },
        Field {
            tag: T::TAG,
            tag_tree: T::TAG_TREE,
            presence: FieldPresence::Required,
            name: "value",
        },
    ]);
}