smbioslib/core/
header.rs

1use serde::{ser::SerializeStruct, Serialize, Serializer};
2use std::{convert::TryInto, fmt, ops::Deref, str::FromStr};
3
4/// # Structure Handle
5///
6/// Each SMBIOS structure has a handle or instance value associated with it.
7/// Some structures will reference other structures by using this value.
8///
9/// Dereference a handle (*handle) to access its u16 value.
10#[derive(Serialize, PartialEq, Eq)]
11pub struct Handle(pub u16);
12
13impl Handle {
14    /// Handle Size (2 bytes)
15    pub const SIZE: usize = 2usize;
16}
17
18impl fmt::Debug for Handle {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        write!(f, "{}", &self.0)
21    }
22}
23
24impl fmt::Display for Handle {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        write!(f, "{}", &self.0)
27    }
28}
29
30impl Deref for Handle {
31    type Target = u16;
32
33    fn deref(&self) -> &Self::Target {
34        &self.0
35    }
36}
37
38impl FromStr for Handle {
39    type Err = std::num::ParseIntError;
40
41    fn from_str(s: &str) -> Result<Self, Self::Err> {
42        Ok(Handle(if s.starts_with("0x") && s.len() > 2 {
43            u16::from_str_radix(&s[2..], 16)?
44        } else {
45            u16::from_str(s)?
46        }))
47    }
48}
49
50/// # SMBIOS Structure Type
51///
52/// Each SMBIOS structure has a type number associated with it.
53///
54/// Dereference a structure type (*struct_type) to access its u8 value.
55#[derive(Serialize)]
56pub struct SMBiosType(pub u8);
57
58impl Deref for SMBiosType {
59    type Target = u8;
60
61    fn deref(&self) -> &Self::Target {
62        &self.0
63    }
64}
65
66impl fmt::Debug for SMBiosType {
67    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
68        fmt.debug_struct(std::any::type_name::<SMBiosType>())
69            .field("type", &self.0)
70            .finish()
71    }
72}
73
74/// # SMBIOS Header
75///
76/// The header part/section of a structure
77pub struct Header([u8; 4]);
78
79impl fmt::Debug for Header {
80    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
81        fmt.debug_struct(std::any::type_name::<Header>())
82            .field("struct_type", &self.struct_type())
83            .field("length", &self.length())
84            .field("handle", &self.handle())
85            .finish()
86    }
87}
88
89impl Serialize for Header {
90    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
91    where
92        S: Serializer,
93    {
94        let mut state = serializer.serialize_struct("Header", 3)?;
95        state.serialize_field("struct_type", &self.struct_type())?;
96        state.serialize_field("length", &self.length())?;
97        state.serialize_field("handle", &self.handle())?;
98        state.end()
99    }
100}
101
102impl Header {
103    /// Total size of a Header (4)
104    ///
105    /// A header has a byte for the _struct_type_ at offset 0,
106    /// a byte for the _length_ at offset 1,
107    /// and a word for the _handle_ at offset 2 for a total of
108    /// 4 bytes.
109    pub const SIZE: usize = 4;
110
111    /// StructType offset (offset 0 and 1 bytes)
112    pub const STRUCT_TYPE_OFFSET: usize = 0;
113
114    /// Length offset (offset 1 and 1 bytes)
115    pub const LENGTH_OFFSET: usize = 1;
116
117    /// Handle offset (offset 2 and 2 bytes)
118    pub const HANDLE_OFFSET: usize = 2;
119
120    /// Creates a new [Header] struct
121    pub fn new(data: [u8; 4]) -> Self {
122        Header(data)
123    }
124
125    /// The type of SMBIOS structure
126    pub fn struct_type(&self) -> u8 {
127        self.0[Self::STRUCT_TYPE_OFFSET] // struct_type is 1 byte at offset 0
128    }
129
130    /// The length of the structure not including the strings part/section
131    pub fn length(&self) -> u8 {
132        self.0[Self::LENGTH_OFFSET] // length is 1 byte at offset 1
133    }
134
135    /// The handle of this structure instance
136    pub fn handle(&self) -> Handle {
137        // handle is 2 bytes at offset 2
138        Handle(u16::from_le_bytes(
139            self.0[Self::HANDLE_OFFSET..Self::HANDLE_OFFSET + 2]
140                .try_into()
141                .expect("u16 is 2 bytes"),
142        ))
143    }
144
145    /// Byte iterator of the header
146    pub fn iter(&self) -> std::slice::Iter<'_, u8> {
147        self.0.iter()
148    }
149}
150
151impl From<[u8; 4]> for Header {
152    fn from(data: [u8; 4]) -> Self {
153        Header(data)
154    }
155}
156
157impl Deref for Header {
158    type Target = [u8; 4];
159
160    fn deref(&self) -> &Self::Target {
161        &self.0
162    }
163}