Skip to main content

lber_serde/
structure.rs

1use common::TagClass;
2
3#[cfg(feature = "serde")]
4extern crate serde;
5
6/// ASN.1 structure prepared for serialization.
7#[derive(Clone, PartialEq, Debug, Eq)]
8pub struct StructureTag {
9    pub class: TagClass,
10    pub id: u64,
11    pub payload: PL,
12}
13
14#[cfg(feature = "serde")]
15impl self::serde::Serialize for StructureTag {
16    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
17    where
18        S: self::serde::Serializer,
19    {
20        use self::serde::ser::SerializeStruct;
21        let mut seq = serializer.serialize_struct("StructureTag", 3)?;
22        seq.serialize_field("class", &self.class)?;
23        seq.serialize_field("element", &self.id)?;
24        match self.payload {
25            PL::P(ref v) => seq.serialize_field("payload", v),
26            PL::C(ref v) => seq.serialize_field("payload", v),
27        }?;
28        seq.end()
29    }
30}
31
32/// Tagged value payload.
33#[derive(Clone, PartialEq, Debug, Eq)]
34pub enum PL {
35    /// Primitive value.
36    P(Vec<u8>),
37    /// Constructed value.
38    C(Vec<StructureTag>),
39}
40
41#[cfg(feature = "serde")]
42impl self::serde::Serialize for PL {
43    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
44    where
45        S: self::serde::Serializer,
46    {
47        match *self {
48            PL::P(ref v) => serializer.serialize_bytes(v),
49            PL::C(ref v) => {
50                use self::serde::ser::SerializeSeq;
51                let mut ser = serializer.serialize_seq(Some(v.len()))?;
52                for e in v {
53                    ser.serialize_element(e)?;
54                }
55                ser.end()
56            }
57        }
58    }
59}
60
61impl StructureTag {
62    pub fn match_class(self, class: TagClass) -> Option<Self> {
63        if self.class == class {
64            Some(self)
65        } else {
66            None
67        }
68    }
69
70    pub fn match_id(self, id: u64) -> Option<Self> {
71        if self.id == id {
72            Some(self)
73        } else {
74            None
75        }
76    }
77
78    pub fn expect_constructed(self) -> Option<Vec<StructureTag>> {
79        match self.payload {
80            PL::P(_) => None,
81            PL::C(i) => Some(i),
82        }
83    }
84
85    pub fn expect_primitive(self) -> Option<Vec<u8>> {
86        match self.payload {
87            PL::P(i) => Some(i),
88            PL::C(_) => None,
89        }
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96    use common::TagClass;
97
98    #[test]
99    fn expect_exact() {
100        let tag = StructureTag {
101            class: TagClass::Application,
102            id: 65u64,
103            payload: PL::C(vec![StructureTag {
104                class: TagClass::Universal,
105                id: 2u64,
106                payload: PL::P(vec![0x16, 0x16]),
107            }]),
108        };
109
110        let out = tag
111            .clone()
112            .match_class(TagClass::Application)
113            .and_then(|x| x.match_id(65u64));
114
115        assert_eq!(out, Some(tag));
116    }
117
118    #[test]
119    fn expect_inner() {
120        let tag = StructureTag {
121            class: TagClass::Application,
122            id: 65u64,
123            payload: PL::C(vec![
124                StructureTag {
125                    class: TagClass::Universal,
126                    id: 2u64,
127                    payload: PL::P(vec![0x16, 0x16]),
128                },
129                StructureTag {
130                    class: TagClass::Application,
131                    id: 3u64,
132                    payload: PL::P(vec![0x3, 0x3]),
133                },
134            ]),
135        };
136
137        let mut subt = tag.expect_constructed().unwrap();
138
139        let b = subt
140            .pop()
141            .unwrap()
142            .match_class(TagClass::Application)
143            .and_then(|x| x.match_id(3));
144        let a = subt
145            .pop()
146            .unwrap()
147            .match_class(TagClass::Universal)
148            .and_then(|x| x.match_id(2));
149
150        assert!(a.is_some());
151        assert!(b.is_some());
152    }
153}