1use crate::common::TagClass;
2
3#[derive(Clone, PartialEq, Debug, Eq)]
5pub struct StructureTag {
6    pub class: TagClass,
7    pub id: u64,
8    pub payload: PL,
9}
10
11#[derive(Clone, PartialEq, Debug, Eq)]
13pub enum PL {
14    P(Vec<u8>),
16    C(Vec<StructureTag>),
18}
19
20impl StructureTag {
21    pub fn match_class(self, class: TagClass) -> Option<Self> {
22        if self.class == class {
23            Some(self)
24        } else {
25            None
26        }
27    }
28
29    pub fn match_id(self, id: u64) -> Option<Self> {
30        if self.id == id { Some(self) } else { None }
31    }
32
33    pub fn expect_constructed(self) -> Option<Vec<StructureTag>> {
34        match self.payload {
35            PL::P(_) => None,
36            PL::C(i) => Some(i),
37        }
38    }
39
40    pub fn expect_primitive(self) -> Option<Vec<u8>> {
41        match self.payload {
42            PL::P(i) => Some(i),
43            PL::C(_) => None,
44        }
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51    use crate::common::TagClass;
52
53    #[test]
54    fn expect_exact() {
55        let tag = StructureTag {
56            class: TagClass::Application,
57            id: 65u64,
58            payload: PL::C(vec![StructureTag {
59                class: TagClass::Universal,
60                id: 2u64,
61                payload: PL::P(vec![0x16, 0x16]),
62            }]),
63        };
64
65        let out = tag
66            .clone()
67            .match_class(TagClass::Application)
68            .and_then(|x| x.match_id(65u64));
69
70        assert_eq!(out, Some(tag));
71    }
72
73    #[test]
74    fn expect_inner() {
75        let tag = StructureTag {
76            class: TagClass::Application,
77            id: 65u64,
78            payload: PL::C(vec![
79                StructureTag {
80                    class: TagClass::Universal,
81                    id: 2u64,
82                    payload: PL::P(vec![0x16, 0x16]),
83                },
84                StructureTag {
85                    class: TagClass::Application,
86                    id: 3u64,
87                    payload: PL::P(vec![0x3, 0x3]),
88                },
89            ]),
90        };
91
92        let mut subt = tag.expect_constructed().unwrap();
93
94        let b = subt
95            .pop()
96            .unwrap()
97            .match_class(TagClass::Application)
98            .and_then(|x| x.match_id(3));
99        let a = subt
100            .pop()
101            .unwrap()
102            .match_class(TagClass::Universal)
103            .and_then(|x| x.match_id(2));
104
105        assert!(a.is_some());
106        assert!(b.is_some());
107    }
108}