smbioslib/core/
smbios_data.rs

1use super::header::Handle;
2use super::undefined_struct::{UndefinedStruct, UndefinedStructTable};
3use crate::structs::{DefinedStructTable, SMBiosStruct};
4use serde::{ser::SerializeStruct, Serialize, Serializer};
5use std::io::Error;
6use std::{cmp::Ordering, slice::Iter};
7use std::{fmt, fs::read};
8
9/// # SMBIOS Data
10///
11/// Contains an optional SMBIOS version and a collection of SMBIOS structures.
12pub struct SMBiosData {
13    table: UndefinedStructTable,
14    /// Version of the contained SMBIOS structures.
15    pub version: Option<SMBiosVersion>,
16}
17
18impl<'a> SMBiosData {
19    /// Creates an SMBIOS table parser which can be iterated
20    ///
21    /// `table` is iterable table data.
22    /// `version` is optional and represents the DMTF SMBIOS Standard version of the bytes in `data`.
23    pub fn new(table: UndefinedStructTable, version: Option<SMBiosVersion>) -> Self {
24        Self { table, version }
25    }
26
27    /// Creates an SMBIOS table parser which can be iterated
28    ///
29    /// `data` is a block of bytes representing the raw table data.
30    /// `version` is optional and represents the DMTF SMBIOS Standard version of the bytes in `data`.
31    pub fn from_vec_and_version(data: Vec<u8>, version: Option<SMBiosVersion>) -> Self {
32        Self {
33            table: UndefinedStructTable::from(data),
34            version,
35        }
36    }
37
38    /// Loads raw SMBios table data from a file
39    pub fn try_load_from_file(
40        filename: &str,
41        version: Option<SMBiosVersion>,
42    ) -> Result<SMBiosData, Error> {
43        let data = read(filename)?;
44        let result = Self {
45            table: UndefinedStructTable::from(data),
46            version,
47        };
48        Ok(result)
49    }
50
51    /// Iterator of the contained [UndefinedStruct] items
52    pub fn iter(&self) -> Iter<'_, UndefinedStruct> {
53        self.table.iter()
54    }
55
56    /// An iterator over the defined type instances within the table.
57    pub fn defined_struct_iter<T: 'a>(&'a self) -> impl Iterator<Item = T> + 'a
58    where
59        T: SMBiosStruct<'a>,
60    {
61        self.table.defined_struct_iter()
62    }
63
64    /// Tests if every element of the defined struct iterator matches a predicate.
65    pub fn all<T, F>(&'a self, f: F) -> bool
66    where
67        T: SMBiosStruct<'a>,
68        F: FnMut(T) -> bool,
69    {
70        self.table.all(f)
71    }
72
73    /// Tests if any element of the defined struct iterator matches a predicate.
74    pub fn any<T, F>(&'a self, f: F) -> bool
75    where
76        T: SMBiosStruct<'a>,
77        F: FnMut(T) -> bool,
78    {
79        self.table.any(f)
80    }
81
82    /// Finds the first occurance of the structure
83    pub fn first<T>(&'a self) -> Option<T>
84    where
85        T: SMBiosStruct<'a>,
86    {
87        self.table.first()
88    }
89
90    /// Finds the first occurance of the structure that satisfies a predicate.
91    pub fn find<T, P>(&'a self, predicate: P) -> Option<T>
92    where
93        T: SMBiosStruct<'a>,
94        P: FnMut(&T) -> bool,
95    {
96        self.table.find(predicate)
97    }
98
99    /// Applies function to the defined struct elements and returns the first non-none result.
100    pub fn find_map<A, B, F>(&'a self, f: F) -> Option<B>
101    where
102        A: SMBiosStruct<'a>,
103        F: FnMut(A) -> Option<B>,
104    {
105        self.table.find_map(f)
106    }
107
108    /// Creates an iterator of the defined structure which uses a closure to determine if an element should be yielded.
109    pub fn filter<T: 'a, P: 'a>(&'a self, predicate: P) -> impl Iterator<Item = T> + 'a
110    where
111        T: SMBiosStruct<'a>,
112        P: FnMut(&T) -> bool,
113    {
114        self.table.filter(predicate)
115    }
116
117    /// Takes a closure and creates an iterator which calls that closure on each defined struct.
118    pub fn map<A: 'a, B: 'a, F: 'a>(&'a self, f: F) -> impl Iterator<Item = B> + 'a
119    where
120        A: SMBiosStruct<'a>,
121        F: FnMut(A) -> B,
122    {
123        self.table.map(f)
124    }
125
126    /// Creates an iterator that both filters and maps from the defined struct iterator.
127    pub fn filter_map<A: 'a, B: 'a, F: 'a>(&'a self, f: F) -> impl Iterator<Item = B> + 'a
128    where
129        A: SMBiosStruct<'a>,
130        F: FnMut(A) -> Option<B>,
131    {
132        self.table.filter_map(f)
133    }
134
135    /// Finds the structure matching the given handle
136    pub fn find_by_handle(&'a self, handle: &Handle) -> Option<&UndefinedStruct> {
137        self.table.find_by_handle(handle)
138    }
139
140    /// Finds all occurances of the structure
141    pub fn collect<T>(&'a self) -> Vec<T>
142    where
143        T: SMBiosStruct<'a>,
144    {
145        self.table.collect()
146    }
147}
148
149impl IntoIterator for SMBiosData {
150    type Item = UndefinedStruct;
151    type IntoIter = std::vec::IntoIter<Self::Item>;
152
153    fn into_iter(self) -> Self::IntoIter {
154        self.table.into_iter()
155    }
156}
157
158impl fmt::Debug for SMBiosData {
159    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
160        // Convert to defined structures to see the structure fields
161        let defined_table: DefinedStructTable<'_> = self.table.iter().collect();
162
163        fmt.debug_struct(std::any::type_name::<SMBiosData>())
164            .field("version", &self.version)
165            .field("table", &defined_table)
166            .finish()
167    }
168}
169
170impl Serialize for SMBiosData {
171    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
172    where
173        S: Serializer,
174    {
175        // Convert to defined structures to see the structure fields
176        let defined_table: DefinedStructTable<'_> = self.table.iter().collect();
177
178        let mut state = serializer.serialize_struct("SMBiosData", 2)?;
179        state.serialize_field("version", &self.version)?;
180        state.serialize_field("table", &defined_table)?;
181        state.end()
182    }
183}
184
185/// # Version of SMBIOS Structure
186#[derive(Debug, Eq, PartialEq, Serialize, Clone, Copy)]
187pub struct SMBiosVersion {
188    /// SMBIOS major version
189    pub major: u8,
190    /// SMBIOS minor version
191    pub minor: u8,
192    /// SMBIOS version revision
193    pub revision: u8,
194}
195
196impl SMBiosVersion {
197    /// Creates a new [SMBiosVersion] struct
198    pub fn new(major: u8, minor: u8, revision: u8) -> SMBiosVersion {
199        SMBiosVersion {
200            major,
201            minor,
202            revision,
203        }
204    }
205}
206
207impl Ord for SMBiosVersion {
208    fn cmp(&self, other: &Self) -> Ordering {
209        if self.major < other.major {
210            Ordering::Less
211        } else if self.major > other.major {
212            Ordering::Greater
213        } else if self.minor < other.minor {
214            Ordering::Less
215        } else if self.minor > other.minor {
216            Ordering::Greater
217        } else if self.revision < other.revision {
218            Ordering::Less
219        } else if self.revision > other.revision {
220            Ordering::Greater
221        } else {
222            Ordering::Equal
223        }
224    }
225}
226
227impl PartialOrd for SMBiosVersion {
228    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
229        Some(self.cmp(other))
230    }
231}