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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use crate::misc::Length;
use crate::Asn1RawDer;
use picky_asn1::tag::{Tag, TagPeeker};
use serde::de::{Error, SeqAccess};
use serde::{de, ser};
use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;

#[derive(Debug, PartialEq, Eq)]
pub struct ApplicationTag<V: Debug + PartialEq, const T: u8>(pub V);

impl<V: Debug + PartialEq, const T: u8> ApplicationTag<V, T> {
    pub fn from(value: V) -> Self {
        Self(value)
    }
}

impl<V: Clone + PartialEq + Debug, const T: u8> Clone for ApplicationTag<V, T> {
    fn clone(&self) -> Self {
        Self(self.0.clone())
    }
}

impl<'de, V: de::Deserialize<'de> + Debug + PartialEq, const T: u8> de::Deserialize<'de> for ApplicationTag<V, T> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        struct Visitor<E, const T: u8>(PhantomData<E>);

        impl<'de, E: de::Deserialize<'de> + Debug + PartialEq, const T: u8> de::Visitor<'de> for Visitor<E, T> {
            type Value = E;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str(&format!("A valid DER-encoded ApplicationTag{:02x}", T))
            }

            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
            where
                A: SeqAccess<'de>,
            {
                #[derive(Debug, serde::Deserialize)]
                struct ApplicationTagInner<V: Debug> {
                    value: V,
                }

                let tag_peeker: TagPeeker = seq
                    .next_element()
                    .map_err(|e| A::Error::custom(format!("Cannot deserialize application tag: {:?}", e)))?
                    .ok_or_else(|| A::Error::missing_field("ApplicationTag"))?;
                let tag = tag_peeker.next_tag;

                if !tag.is_application() {
                    return Err(A::Error::custom(format!(
                        "Expected Application class tag but got: {:?}",
                        tag.class()
                    )));
                }

                if tag.number() != T {
                    return Err(A::Error::custom(format!(
                        "Expected Application number tag {} but got: {}",
                        T,
                        tag.number()
                    )));
                }

                let rest: ApplicationTagInner<E> = seq
                    .next_element()
                    .map_err(|e| A::Error::custom(format!("Cannot deserialize application tag inner value: {:?}", e)))?
                    .ok_or_else(|| A::Error::missing_field("ApplicationInnerValue"))?;

                Ok(rest.value)
            }
        }

        let inner = deserializer
            .deserialize_enum("ApplicationTag", &["ApplicationTag"], Visitor::<V, T>(PhantomData))
            .map_err(D::Error::custom)?;

        Ok(Self(inner))
    }
}

impl<V: ser::Serialize + Debug + PartialEq + Clone, const T: u8> ser::Serialize for ApplicationTag<V, T> {
    fn serialize<S>(&self, serializer: S) -> Result<<S as ser::Serializer>::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        use serde::ser::Error;

        let mut buff = Vec::new();
        {
            let mut s = crate::Serializer::new_to_byte_buf(&mut buff);
            self.0
                .serialize(&mut s)
                .map_err(|e| S::Error::custom(format!("Cannot serialize Application tag inner value: {:?}", e)))?;
        }

        let mut res = vec![Tag::application_constructed(T).inner()];

        Length::serialize(buff.len(), &mut res)
            .map_err(|e| S::Error::custom(format!("Cannot serialize Length: {:?}", e)))?;
        res.extend_from_slice(&buff);

        Asn1RawDer(res).serialize(serializer)
    }
}

#[cfg(test)]
mod tests {
    use crate::application_tag::ApplicationTag;
    use picky_asn1::restricted_string::Utf8String;
    use picky_asn1::wrapper::Utf8StringAsn1;

    #[test]
    fn test_application_tag() {
        let expected_raw = vec![106, 13, 12, 11, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109];
        let expected: ApplicationTag<Utf8StringAsn1, 10> = ApplicationTag::from(Utf8StringAsn1::from(
            Utf8String::from_string("example.com".to_owned()).unwrap(),
        ));

        let app_10: ApplicationTag<Utf8StringAsn1, 10> = crate::from_bytes(&expected_raw).unwrap();
        let app_10_raw = crate::to_vec(&app_10).unwrap();

        assert_eq!(expected, app_10);
        assert_eq!(expected_raw, app_10_raw);
    }
}