1use super::*;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct Entry<'a> {
14 pub key: KeyType,
15 pub data: EntryData<'a>,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum KeyType {
21 Descriptor,
22 BusDependentInfo,
23 Vendor,
24 HardwareVersion,
25 Module,
26 NodeCapabilities,
27 Eui64,
28 Unit,
29 SpecifierId,
30 Version,
31 DependentInfo,
32 UnitLocation,
33 Model,
34 Instance,
35 Keyword,
36 Feature,
37 ModifiableDescriptor,
38 DirectoryId,
39 Reserved(u8),
40}
41
42impl From<u8> for KeyType {
43 fn from(val: u8) -> Self {
44 match val {
45 0x01 => KeyType::Descriptor,
46 0x02 => KeyType::BusDependentInfo,
47 0x03 => KeyType::Vendor,
48 0x04 => KeyType::HardwareVersion,
49 0x07 => KeyType::Module,
50 0x0c => KeyType::NodeCapabilities,
51 0x0d => KeyType::Eui64,
52 0x11 => KeyType::Unit,
53 0x12 => KeyType::SpecifierId,
54 0x13 => KeyType::Version,
55 0x14 => KeyType::DependentInfo,
56 0x15 => KeyType::UnitLocation,
57 0x17 => KeyType::Model,
58 0x18 => KeyType::Instance,
59 0x19 => KeyType::Keyword,
60 0x1a => KeyType::Feature,
61 0x1f => KeyType::ModifiableDescriptor,
62 0x20 => KeyType::DirectoryId,
63 _ => KeyType::Reserved(val),
64 }
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
70pub enum EntryData<'a> {
71 Immediate(u32),
72 CsrOffset(usize),
73 Leaf(&'a [u8]),
74 Directory(Vec<Entry<'a>>),
75}
76
77pub trait EntryDataAccess<'a, T> {
79 fn get(&'a self, key_type: KeyType) -> Option<T>;
80}
81
82impl<'a> EntryDataAccess<'a, &'a u32> for Entry<'a> {
83 fn get(&'a self, key_type: KeyType) -> Option<&'a u32> {
84 if self.key == key_type {
85 if let EntryData::Immediate(v) = &self.data {
86 Some(v)
87 } else {
88 None
89 }
90 } else {
91 None
92 }
93 }
94}
95
96impl<'a> EntryDataAccess<'a, &'a usize> for Entry<'a> {
97 fn get(&'a self, key_type: KeyType) -> Option<&'a usize> {
98 if self.key == key_type {
99 if let EntryData::CsrOffset(o) = &self.data {
100 Some(o)
101 } else {
102 None
103 }
104 } else {
105 None
106 }
107 }
108}
109
110impl<'a> EntryDataAccess<'a, &'a [Entry<'a>]> for Entry<'a> {
111 fn get(&'a self, key_type: KeyType) -> Option<&'a [Entry<'a>]> {
112 if self.key == key_type {
113 if let EntryData::Directory(d) = &self.data {
114 Some(d)
115 } else {
116 None
117 }
118 } else {
119 None
120 }
121 }
122}
123
124impl<'a> EntryDataAccess<'a, u32> for Entry<'a> {
126 fn get(&'a self, key_type: KeyType) -> Option<u32> {
127 EntryDataAccess::<&u32>::get(self, key_type).map(|v| *v)
128 }
129}
130
131impl<'a> EntryDataAccess<'a, usize> for Entry<'a> {
132 fn get(&'a self, key_type: KeyType) -> Option<usize> {
133 EntryDataAccess::<&usize>::get(self, key_type).map(|v| *v)
134 }
135}
136
137impl<'a> EntryDataAccess<'a, DescriptorLeaf<'a>> for Entry<'a> {
139 fn get(&'a self, key_type: KeyType) -> Option<DescriptorLeaf<'a>> {
140 if self.key == key_type {
141 DescriptorLeaf::try_from(self).ok()
142 } else {
143 None
144 }
145 }
146}
147
148impl<'a> EntryDataAccess<'a, TextualDescriptorData<'a>> for Entry<'a> {
149 fn get(&'a self, key_type: KeyType) -> Option<TextualDescriptorData<'a>> {
150 EntryDataAccess::<DescriptorLeaf<'a>>::get(self, key_type).and_then(|desc| {
151 if let DescriptorData::Textual(d) = desc.data {
152 Some(d)
153 } else {
154 None
155 }
156 })
157 }
158}
159
160impl<'a> EntryDataAccess<'a, &'a str> for Entry<'a> {
161 fn get(&'a self, key_type: KeyType) -> Option<&'a str> {
162 EntryDataAccess::<TextualDescriptorData<'a>>::get(self, key_type).map(|data| data.text)
163 }
164}
165
166impl<'a> EntryDataAccess<'a, String> for Entry<'a> {
167 fn get(&'a self, key_type: KeyType) -> Option<String> {
168 EntryDataAccess::<&str>::get(self, key_type).map(|text| text.to_string())
169 }
170}
171
172impl<'a> EntryDataAccess<'a, Eui64Leaf> for Entry<'a> {
174 fn get(&'a self, key_type: KeyType) -> Option<Eui64Leaf> {
175 if self.key == key_type {
176 Eui64Leaf::try_from(self).ok()
177 } else {
178 None
179 }
180 }
181}
182
183impl<'a> EntryDataAccess<'a, u64> for Entry<'a> {
184 fn get(&'a self, key_type: KeyType) -> Option<u64> {
185 EntryDataAccess::<Eui64Leaf>::get(self, key_type).map(|data| data.0)
186 }
187}
188
189impl<'a> EntryDataAccess<'a, UnitLocationLeaf> for Entry<'a> {
190 fn get(&'a self, key_type: KeyType) -> Option<UnitLocationLeaf> {
191 if self.key == key_type {
192 UnitLocationLeaf::try_from(self).ok()
193 } else {
194 None
195 }
196 }
197}