1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use std::{convert::TryInto, fmt, ops::Deref, str::FromStr};

/// # Structure Handle
///
/// Each SMBIOS structure has a handle or instance value associated with it.
/// Some structures will reference other structures by using this value.
///
/// Dereference a handle (*handle) to access its u16 value.
#[derive(Debug, PartialEq, Eq)]
pub struct Handle(pub u16);

impl Handle {
    /// Handle Size (2 bytes)
    pub const SIZE: usize = 2usize;
}

impl Deref for Handle {
    type Target = u16;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl FromStr for Handle {
    type Err = std::num::ParseIntError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Handle(if s.starts_with("0x") && s.len() > 2 {
            u16::from_str_radix(&s[2..], 16)?
        } else {
            u16::from_str(s)?
        }))
    }
}

/// # SMBIOS Structure Type
///
/// Each SMBIOS structure has a type number associated with it.
///
/// Dereference a structure type (*struct_type) to access its u8 value.
pub struct SMBiosType(pub u8);

impl Deref for SMBiosType {
    type Target = u8;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl fmt::Debug for SMBiosType {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt.debug_struct(std::any::type_name::<SMBiosType>())
            .field("type", &self.0)
            .finish()
    }
}

/// # SMBIOS Header
///
/// The header part/section of a structure
pub struct Header([u8; 4]);

impl fmt::Debug for Header {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt.debug_struct(std::any::type_name::<Header>())
            .field("struct_type", &self.struct_type())
            .field("length", &self.length())
            .field("handle", &self.handle())
            .finish()
    }
}

impl Header {
    /// Total size of a Header (4)
    ///
    /// A header has a byte for the _struct_type_ at offset 0,
    /// a byte for the _length_ at offset 1,
    /// and a word for the _handle_ at offset 2 for a total of
    /// 4 bytes.
    pub const SIZE: usize = 4;

    /// StructType offset (offset 0 and 1 bytes)
    pub const STRUCT_TYPE_OFFSET: usize = 0;

    /// Length offset (offset 1 and 1 bytes)
    pub const LENGTH_OFFSET: usize = 1;

    /// Handle offset (offset 2 and 2 bytes)
    pub const HANDLE_OFFSET: usize = 2;

    /// Creates a new [Header] struct
    pub fn new(data: [u8; 4]) -> Self {
        Header(data)
    }

    /// The type of SMBIOS structure
    pub fn struct_type(&self) -> u8 {
        self.0[Self::STRUCT_TYPE_OFFSET] // struct_type is 1 byte at offset 0
    }

    /// The length of the structure not including the strings part/section
    pub fn length(&self) -> u8 {
        self.0[Self::LENGTH_OFFSET] // length is 1 byte at offset 1
    }

    /// The handle of this structure instance
    pub fn handle(&self) -> Handle {
        // handle is 2 bytes at offset 2
        Handle(u16::from_le_bytes(
            self.0[Self::HANDLE_OFFSET..Self::HANDLE_OFFSET + 2]
                .try_into()
                .expect("u16 is 2 bytes"),
        ))
    }

    /// Byte iterator of the header
    pub fn iter(&self) -> std::slice::Iter<'_, u8> {
        self.0.iter()
    }
}

impl From<[u8; 4]> for Header {
    fn from(data: [u8; 4]) -> Self {
        Header(data)
    }
}

impl Deref for Header {
    type Target = [u8; 4];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}