1use crate::core::{strings::*, UndefinedStruct};
2use crate::SMBiosStruct;
3use serde::{ser::SerializeStruct, Serialize, Serializer};
4use std::{
5 array::TryFromSliceError,
6 convert::{TryFrom, TryInto},
7 fmt,
8 ops::Deref,
9};
10
11pub struct SMBiosSystemInformation<'a> {
21 parts: &'a UndefinedStruct,
22}
23
24impl<'a> SMBiosStruct<'a> for SMBiosSystemInformation<'a> {
25 const STRUCT_TYPE: u8 = 1u8;
26
27 fn new(parts: &'a UndefinedStruct) -> Self {
28 Self { parts }
29 }
30
31 fn parts(&self) -> &'a UndefinedStruct {
32 self.parts
33 }
34}
35
36impl<'a> SMBiosSystemInformation<'a> {
37 pub fn manufacturer(&self) -> SMBiosString {
39 self.parts.get_field_string(0x04)
40 }
41
42 pub fn product_name(&self) -> SMBiosString {
44 self.parts.get_field_string(0x05)
45 }
46
47 pub fn version(&self) -> SMBiosString {
49 self.parts.get_field_string(0x06)
50 }
51
52 pub fn serial_number(&self) -> SMBiosString {
54 self.parts.get_field_string(0x07)
55 }
56
57 pub fn uuid(&self) -> Option<SystemUuidData> {
59 self.parts
60 .get_field_data(0x08, 0x18)
61 .map(|raw| SystemUuidData::try_from(raw).expect("A GUID is 0x10 bytes"))
62 }
63
64 pub fn wakeup_type(&self) -> Option<SystemWakeUpTypeData> {
68 self.parts
69 .get_field_byte(0x18)
70 .map(|raw| SystemWakeUpTypeData::from(raw))
71 }
72
73 pub fn sku_number(&self) -> SMBiosString {
85 self.parts.get_field_string(0x19)
86 }
87
88 pub fn family(&self) -> SMBiosString {
100 self.parts.get_field_string(0x1A)
101 }
102}
103
104impl fmt::Debug for SMBiosSystemInformation<'_> {
105 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
106 fmt.debug_struct(std::any::type_name::<SMBiosSystemInformation<'_>>())
107 .field("header", &self.parts.header)
108 .field("manufacturer", &self.manufacturer())
109 .field("product_name", &self.product_name())
110 .field("version", &self.version())
111 .field("serial_number", &self.serial_number())
112 .field("uuid", &self.uuid())
113 .field("wakeup_type", &self.wakeup_type())
114 .field("sku_number", &self.sku_number())
115 .field("family", &self.family())
116 .finish()
117 }
118}
119
120impl Serialize for SMBiosSystemInformation<'_> {
121 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
122 where
123 S: Serializer,
124 {
125 let mut state = serializer.serialize_struct("SMBiosSystemInformation", 9)?;
126 state.serialize_field("header", &self.parts.header)?;
127 state.serialize_field("manufacturer", &self.manufacturer())?;
128 state.serialize_field("product_name", &self.product_name())?;
129 state.serialize_field("version", &self.version())?;
130 state.serialize_field("serial_number", &self.serial_number())?;
131 state.serialize_field("uuid", &self.uuid())?;
132 state.serialize_field("wakeup_type", &self.wakeup_type())?;
133 state.serialize_field("sku_number", &self.sku_number())?;
134 state.serialize_field("family", &self.family())?;
135 state.end()
136 }
137}
138
139#[derive(Serialize, Debug)]
141pub enum SystemUuidData {
142 IdNotPresentButSettable,
144 IdNotPresent,
146 Uuid(SystemUuid),
148}
149
150impl SystemUuidData {
151 fn new<'a>(array: &'a [u8; 0x10]) -> SystemUuidData {
152 if array.iter().all(|&x| x == 0) {
153 SystemUuidData::IdNotPresentButSettable
154 } else if array.iter().all(|&x| x == 0xFF) {
155 SystemUuidData::IdNotPresent
156 } else {
157 SystemUuidData::Uuid(SystemUuid::from(array))
158 }
159 }
160}
161
162impl<'a> TryFrom<&'a [u8]> for SystemUuidData {
163 type Error = TryFromSliceError;
164
165 fn try_from(raw: &'a [u8]) -> Result<Self, Self::Error> {
166 <&[u8; 0x10]>::try_from(raw).and_then(|array| Ok(SystemUuidData::new(array)))
167 }
168}
169
170impl fmt::Display for SystemUuidData {
171 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172 match &*self {
173 SystemUuidData::IdNotPresent => write!(f, "IdNotPresent"),
174 SystemUuidData::IdNotPresentButSettable => write!(f, "IdNotPresentButSettable"),
175 SystemUuidData::Uuid(_system_uuid) => write!(f, "{}", &_system_uuid),
176 }
177 }
178}
179
180#[derive(PartialEq, Eq)]
182pub struct SystemUuid {
183 pub raw: [u8; 0x10],
185}
186
187impl SystemUuid {
188 pub fn time_low(&self) -> u32 {
190 u32::from_le_bytes(self.raw[..0x4].try_into().expect("incorrect size"))
191 }
192
193 pub fn time_mid(&self) -> u16 {
195 u16::from_le_bytes(self.raw[0x4..0x6].try_into().expect("incorrect size"))
196 }
197
198 pub fn time_high_and_version(&self) -> u16 {
200 u16::from_le_bytes(self.raw[0x6..0x8].try_into().expect("incorrect size"))
201 }
202
203 pub fn clock_seq_high_and_reserved(&self) -> u8 {
205 self.raw[0x8]
206 }
207
208 pub fn clock_seq_low(&self) -> u8 {
210 self.raw[0x9]
211 }
212
213 pub fn node(&self) -> &[u8; 6] {
215 self.raw[0xA..0x10].try_into().expect("incorrect size")
216 }
217}
218
219impl<'a> From<&'a [u8; 0x10]> for SystemUuid {
220 fn from(raw: &'a [u8; 0x10]) -> Self {
221 SystemUuid { raw: raw.clone() }
222 }
223}
224
225impl fmt::Display for SystemUuid {
226 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227 write!(
237 f,
238 "{:08x}-{:04x}-{:04x}-{:02x}{:02x}-",
239 self.time_low(),
240 self.time_mid(),
241 self.time_high_and_version(),
242 self.clock_seq_high_and_reserved(),
243 self.clock_seq_low()
244 )?;
245
246 self.node().iter().fold(Ok(()), |result, node_byte| {
247 result.and_then(|_| write!(f, "{:02x}", node_byte))
248 })
249 }
250}
251
252impl fmt::Debug for SystemUuid {
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 write!(f, "{}", &self)
255 }
256}
257
258impl Serialize for SystemUuid {
259 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
260 where
261 S: Serializer,
262 {
263 serializer.serialize_str(format!("{}", self).as_str())
264 }
265}
266
267pub struct SystemWakeUpTypeData {
269 pub raw: u8,
276 pub value: SystemWakeUpType,
278}
279
280impl fmt::Debug for SystemWakeUpTypeData {
281 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
282 fmt.debug_struct(std::any::type_name::<SystemWakeUpTypeData>())
283 .field("raw", &self.raw)
284 .field("value", &self.value)
285 .finish()
286 }
287}
288
289impl Serialize for SystemWakeUpTypeData {
290 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
291 where
292 S: Serializer,
293 {
294 let mut state = serializer.serialize_struct("SystemWakeUpTypeData", 2)?;
295 state.serialize_field("raw", &self.raw)?;
296 state.serialize_field("value", &self.value)?;
297 state.end()
298 }
299}
300
301impl fmt::Display for SystemWakeUpTypeData {
302 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303 match &self.value {
304 SystemWakeUpType::None => write!(f, "{}", &self.raw),
305 _ => write!(f, "{:?}", &self.value),
306 }
307 }
308}
309
310impl Deref for SystemWakeUpTypeData {
311 type Target = SystemWakeUpType;
312
313 fn deref(&self) -> &Self::Target {
314 &self.value
315 }
316}
317
318#[derive(Serialize, Debug, PartialEq, Eq)]
320pub enum SystemWakeUpType {
321 Other,
323 Unknown,
325 ApmTimer,
327 ModernRing,
329 LanRemote,
331 PowerSwitch,
333 PciPme,
335 ACPowerRestored,
337 None,
339}
340
341impl From<u8> for SystemWakeUpTypeData {
342 fn from(raw: u8) -> Self {
343 SystemWakeUpTypeData {
344 value: match raw {
345 0x01 => SystemWakeUpType::Other,
346 0x02 => SystemWakeUpType::Unknown,
347 0x03 => SystemWakeUpType::ApmTimer,
348 0x04 => SystemWakeUpType::ModernRing,
349 0x05 => SystemWakeUpType::LanRemote,
350 0x06 => SystemWakeUpType::PowerSwitch,
351 0x07 => SystemWakeUpType::PciPme,
352 0x08 => SystemWakeUpType::ACPowerRestored,
353 _ => SystemWakeUpType::None,
354 },
355 raw,
356 }
357 }
358}
359
360#[cfg(test)]
361mod tests {
362 use super::*;
363
364 #[test]
365 fn unit_test() {
366 let struct_type1 = vec![
367 0x01, 0x1B, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0xD2, 0x01, 0x25, 0x3E, 0x48, 0xE6,
368 0x11, 0xE8, 0xBA, 0xD3, 0x70, 0x20, 0x84, 0x0F, 0x9D, 0x47, 0x06, 0x05, 0x06, b'L',
369 b'E', b'N', b'O', b'V', b'O', 0x00, b'3', b'0', b'B', b'F', b'S', b'0', b'7', b'5',
370 b'0', b'0', 0x00, b'T', b'h', b'i', b'n', b'k', b'S', b't', b'a', b't', b'i', b'o',
371 b'n', b' ', b'P', b'5', b'2', b'0', 0x00, b'M', b'N', b'0', b'6', b'P', b'Q', b'R',
372 b'S', 0x00, b'L', b'E', b'N', b'O', b'V', b'O', b'_', b'M', b'T', b'_', b'3', b'0',
373 b'B', b'F', b'_', b'B', b'U', b'_', b'T', b'h', b'i', b'n', b'k', b'_', b'F', b'M',
374 b'_', b'T', b'h', b'i', b'n', b'k', b'S', b't', b'a', b't', b'i', b'o', b'n', b' ',
375 b'P', b'5', b'2', b'0', 0x00, b'T', b'h', b'i', b'n', b'k', b'S', b't', b'a', b't',
376 b'i', b'o', b'n', b' ', b'P', b'5', b'2', b'0', 0x00, 0x00,
377 ];
378
379 let parts = UndefinedStruct::new(&struct_type1);
380 let test_struct = SMBiosSystemInformation::new(&parts);
381
382 assert_eq!(test_struct.manufacturer().to_string(), "LENOVO".to_string());
383 assert_eq!(
384 test_struct.product_name().to_string(),
385 "30BFS07500".to_string()
386 );
387 assert_eq!(
388 test_struct.version().to_string(),
389 "ThinkStation P520".to_string()
390 );
391 assert_eq!(
392 test_struct.serial_number().to_string(),
393 "MN06PQRS".to_string()
394 );
395 assert_eq!(
396 format!("{:?}", test_struct.uuid()),
397 "Some(Uuid(3e2501d2-e648-e811-bad3-7020840f9d47))".to_string()
398 );
399 assert_eq!(
400 *test_struct.wakeup_type().unwrap(),
401 SystemWakeUpType::PowerSwitch
402 );
403 assert_eq!(
404 test_struct.sku_number().to_string(),
405 "LENOVO_MT_30BF_BU_Think_FM_ThinkStation P520".to_string()
406 );
407 assert_eq!(
408 test_struct.family().to_string(),
409 "ThinkStation P520".to_string()
410 );
411 }
412}