smbioslib/structs/types/
group_associations.rs

1use crate::core::{strings::*, Handle, UndefinedStruct};
2use crate::SMBiosStruct;
3use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer};
4use std::fmt;
5
6/// # Group Associations (Type 14)
7///
8/// The Group Associations structure is provided for OEMs who want to specify the arrangement or hierarchy
9/// of certain components (including other Group Associations) within the system. For example, you can use
10/// the Group Associations structure to indicate that two CPUs share a common external cache system.
11///
12/// Compliant with:
13/// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134)
14/// Document Date: 2020-07-17
15pub struct SMBiosGroupAssociations<'a> {
16    parts: &'a UndefinedStruct,
17}
18
19impl<'a> SMBiosStruct<'a> for SMBiosGroupAssociations<'a> {
20    const STRUCT_TYPE: u8 = 14u8;
21
22    fn new(parts: &'a UndefinedStruct) -> Self {
23        Self { parts }
24    }
25
26    fn parts(&self) -> &'a UndefinedStruct {
27        self.parts
28    }
29}
30
31impl<'a> SMBiosGroupAssociations<'a> {
32    /// A string describing the group
33    pub fn group_name(&self) -> SMBiosString {
34        self.parts.get_field_string(0x4)
35    }
36
37    /// Number of [GroupAssociationItem] entries
38    pub fn number_of_items(&self) -> Option<usize> {
39        let length = self.parts.header.length() as usize;
40
41        if length < GroupAssociationItemIterator::ITEMS_OFFSET {
42            return None;
43        }
44
45        let byte_count = length - GroupAssociationItemIterator::ITEMS_OFFSET;
46
47        if byte_count % GroupAssociationItem::SIZE != 0 {
48            return None;
49        }
50
51        Some(byte_count / GroupAssociationItem::SIZE)
52    }
53
54    /// Iterates over the [GroupAssociationItem] entries
55    pub fn item_iterator(&'a self) -> GroupAssociationItemIterator<'a> {
56        GroupAssociationItemIterator::new(self)
57    }
58}
59
60impl fmt::Debug for SMBiosGroupAssociations<'_> {
61    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
62        fmt.debug_struct(std::any::type_name::<SMBiosGroupAssociations<'_>>())
63            .field("header", &self.parts.header)
64            .field("group_name", &self.group_name())
65            .field("number_of_items", &self.number_of_items())
66            .field("item_iterator", &self.item_iterator())
67            .finish()
68    }
69}
70
71impl Serialize for SMBiosGroupAssociations<'_> {
72    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
73    where
74        S: Serializer,
75    {
76        let mut state = serializer.serialize_struct("SMBiosGroupAssociations", 4)?;
77        state.serialize_field("header", &self.parts.header)?;
78        state.serialize_field("group_name", &self.group_name())?;
79        state.serialize_field("number_of_items", &self.number_of_items())?;
80        state.serialize_field("item_iterator", &self.item_iterator())?;
81        state.end()
82    }
83}
84
85/// # Group Association Item contained within [SMBiosGroupAssociations]
86pub struct GroupAssociationItem<'a> {
87    group_associations: &'a SMBiosGroupAssociations<'a>,
88    entry_offset: usize,
89}
90
91impl<'a> GroupAssociationItem<'a> {
92    /// Size in bytes of a GroupAssociationItem
93    const SIZE: usize = 3usize;
94
95    fn new(group_associations: &'a SMBiosGroupAssociations<'a>, entry_offset: usize) -> Self {
96        Self {
97            group_associations,
98            entry_offset,
99        }
100    }
101
102    /// Item Type
103    ///
104    /// Item (Structure) Type of this member
105    pub fn struct_type(&self) -> Option<u8> {
106        self.group_associations
107            .parts()
108            .get_field_byte(self.entry_offset)
109    }
110
111    /// Item Handle
112    ///
113    /// Handle corresponding to this structure
114    pub fn item_handle(&self) -> Option<Handle> {
115        self.group_associations
116            .parts()
117            .get_field_handle(self.entry_offset + 1)
118    }
119}
120
121impl fmt::Debug for GroupAssociationItem<'_> {
122    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
123        fmt.debug_struct(std::any::type_name::<GroupAssociationItem<'_>>())
124            .field("struct_type", &self.struct_type())
125            .field("item_handle", &self.item_handle())
126            .finish()
127    }
128}
129
130impl Serialize for GroupAssociationItem<'_> {
131    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
132    where
133        S: Serializer,
134    {
135        let mut state = serializer.serialize_struct("GroupAssociationItem", 2)?;
136        state.serialize_field("struct_type", &self.struct_type())?;
137        state.serialize_field("item_handle", &self.item_handle())?;
138        state.end()
139    }
140}
141
142/// Iterates over the [GroupAssociationItem] entries contained within [SMBiosGroupAssociations]
143pub struct GroupAssociationItemIterator<'a> {
144    data: &'a SMBiosGroupAssociations<'a>,
145    current_index: usize,
146    current_entry: usize,
147    number_of_entries: usize,
148}
149
150impl<'a> GroupAssociationItemIterator<'a> {
151    const ITEMS_OFFSET: usize = 5usize;
152
153    fn new(data: &'a SMBiosGroupAssociations<'a>) -> Self {
154        GroupAssociationItemIterator {
155            data: data,
156            current_index: Self::ITEMS_OFFSET,
157            current_entry: 0,
158            number_of_entries: data.number_of_items().unwrap_or(0),
159        }
160    }
161
162    fn reset(&mut self) {
163        self.current_index = Self::ITEMS_OFFSET;
164        self.current_entry = 0;
165    }
166}
167
168impl<'a> IntoIterator for &'a GroupAssociationItemIterator<'a> {
169    type Item = GroupAssociationItem<'a>;
170    type IntoIter = GroupAssociationItemIterator<'a>;
171
172    fn into_iter(self) -> Self::IntoIter {
173        GroupAssociationItemIterator {
174            data: self.data,
175            current_index: GroupAssociationItemIterator::ITEMS_OFFSET,
176            current_entry: 0,
177            number_of_entries: self.data.number_of_items().unwrap_or(0),
178        }
179    }
180}
181
182impl<'a> Iterator for GroupAssociationItemIterator<'a> {
183    type Item = GroupAssociationItem<'a>;
184
185    fn next(&mut self) -> Option<Self::Item> {
186        if self.current_entry == self.number_of_entries {
187            self.reset();
188            return None;
189        }
190
191        let next_index = self.current_index + GroupAssociationItem::SIZE;
192        match self
193            .data
194            .parts()
195            .get_field_data(self.current_index, next_index)
196        {
197            Some(_entry_block) => {
198                let result = GroupAssociationItem::new(self.data, self.current_index);
199                self.current_index = next_index;
200                self.current_entry += 1;
201                Some(result)
202            }
203            None => {
204                self.reset();
205                None
206            }
207        }
208    }
209}
210
211impl<'a> fmt::Debug for GroupAssociationItemIterator<'a> {
212    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
213        fmt.debug_list().entries(self.into_iter()).finish()
214    }
215}
216
217impl<'a> Serialize for GroupAssociationItemIterator<'a> {
218    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
219    where
220        S: Serializer,
221    {
222        let items: Vec<GroupAssociationItem<'_>> = self.into_iter().collect();
223        let mut seq = serializer.serialize_seq(Some(items.len()))?;
224        for e in items {
225            seq.serialize_element(&e)?;
226        }
227        seq.end()
228    }
229}
230
231#[cfg(test)]
232mod tests {
233    use super::*;
234
235    #[test]
236    fn unit_test() {
237        let struct_type14 = vec![
238            0x0E, 0x08, 0x5F, 0x00, 0x01, 0xDD, 0x5B, 0x00, 0x46, 0x69, 0x72, 0x6D, 0x77, 0x61,
239            0x72, 0x65, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x49, 0x6E, 0x66,
240            0x6F, 0x00, 0x00,
241        ];
242
243        let parts = UndefinedStruct::new(&struct_type14);
244        let test_struct = SMBiosGroupAssociations::new(&parts);
245
246        println!("{:?}", test_struct);
247
248        assert_eq!(
249            test_struct.group_name().to_string(),
250            "Firmware Version Info".to_string()
251        );
252        let mut iterator = test_struct.item_iterator().into_iter();
253        let first_item = iterator.next().unwrap();
254        assert_eq!(first_item.struct_type(), Some(221));
255        assert_eq!(*first_item.item_handle().unwrap(), 91);
256    }
257}