ieee1212_config_rom/
entry.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! For directory entries, the module includes structure, enumeration and trait implementation.
5//!
6//! Entry structure expresss directory entry. KeyType enumerations expresss key of entry.
7//! EntryData enumeration expresss type of directory entry, including its content.
8
9use super::*;
10
11/// The structure to express directory entry.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct Entry<'a> {
14    pub key: KeyType,
15    pub data: EntryData<'a>,
16}
17
18/// The enumeration to express key of directory entry.
19#[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/// The enumeration to express type of directory entry and its content.
69#[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
77/// The trait to access to data of entry according to key and data type.
78pub 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
124// Cloned type.
125impl<'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
137// Via descriptor data.
138impl<'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
172// Via EUI-64 leaf data.
173impl<'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}