use crate::core::{Handle, UndefinedStruct};
use crate::SMBiosStruct;
use std::fmt;
use std::ops::Deref;
pub struct SMBiosBaseboardInformation<'a> {
parts: &'a UndefinedStruct,
}
impl<'a> SMBiosStruct<'a> for SMBiosBaseboardInformation<'a> {
const STRUCT_TYPE: u8 = 2u8;
fn new(parts: &'a UndefinedStruct) -> Self {
Self { parts }
}
fn parts(&self) -> &'a UndefinedStruct {
self.parts
}
}
impl<'a> SMBiosBaseboardInformation<'a> {
pub fn manufacturer(&self) -> Option<String> {
self.parts.get_field_string(0x04)
}
pub fn product(&self) -> Option<String> {
self.parts.get_field_string(0x05)
}
pub fn version(&self) -> Option<String> {
self.parts.get_field_string(0x06)
}
pub fn serial_number(&self) -> Option<String> {
self.parts.get_field_string(0x07)
}
pub fn asset_tag(&self) -> Option<String> {
self.parts.get_field_string(0x08)
}
pub fn feature_flags(&self) -> Option<BaseboardFeatures> {
self.parts
.get_field_byte(0x09)
.map(|raw| BaseboardFeatures::from(raw))
}
pub fn location_in_chassis(&self) -> Option<String> {
self.parts.get_field_string(0x0A)
}
pub fn chassis_handle(&self) -> Option<Handle> {
self.parts.get_field_handle(0x0B)
}
pub fn board_type(&self) -> Option<BoardTypeData> {
self.parts
.get_field_byte(0x0D)
.map(|raw| BoardTypeData::from(raw))
}
pub fn number_of_contained_object_handles(&self) -> Option<u8> {
self.parts.get_field_byte(0x0E)
}
pub fn contained_object_handle_iterator(&'a self) -> ObjectHandleIterator<'a> {
ObjectHandleIterator::new(self)
}
}
impl fmt::Debug for SMBiosBaseboardInformation<'_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct(std::any::type_name::<SMBiosBaseboardInformation<'_>>())
.field("header", &self.parts.header)
.field("manufacturer", &self.manufacturer())
.field("product", &self.product())
.field("version", &self.version())
.field("serial_number", &self.serial_number())
.field("asset_tag", &self.asset_tag())
.field("feature_flags", &self.feature_flags())
.field("location_in_chassis", &self.location_in_chassis())
.field("chassis_handle", &self.chassis_handle())
.field("board_type", &self.board_type())
.field(
"number_of_contained_object_handles",
&self.number_of_contained_object_handles(),
)
.field(
"contained_object_handle_iterator",
&self.contained_object_handle_iterator(),
)
.finish()
}
}
pub struct BoardTypeData {
pub raw: u8,
pub value: BoardType,
}
impl fmt::Debug for BoardTypeData {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct(std::any::type_name::<BoardTypeData>())
.field("raw", &self.raw)
.field("value", &self.value)
.finish()
}
}
impl Deref for BoardTypeData {
type Target = BoardType;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl From<u8> for BoardTypeData {
fn from(raw: u8) -> Self {
BoardTypeData {
value: match raw {
0x01 => BoardType::Other,
0x02 => BoardType::Unknown,
0x03 => BoardType::ServerBlade,
0x04 => BoardType::ConnectivitySwitch,
0x05 => BoardType::SystemManagementModule,
0x06 => BoardType::ProcessorModule,
0x07 => BoardType::IOModule,
0x08 => BoardType::MemoryModule,
0x09 => BoardType::Daughterboard,
0x0A => BoardType::Motherboard,
0x0B => BoardType::ProcessorMemoryModule,
0x0C => BoardType::ProcessorIOModule,
0x0D => BoardType::InterconnectBoard,
_ => BoardType::None,
},
raw,
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum BoardType {
Unknown,
Other,
ServerBlade,
ConnectivitySwitch,
SystemManagementModule,
ProcessorModule,
IOModule,
MemoryModule,
Daughterboard,
Motherboard,
ProcessorMemoryModule,
ProcessorIOModule,
InterconnectBoard,
None,
}
#[derive(PartialEq, Eq)]
pub struct BaseboardFeatures {
raw: u8,
}
impl Deref for BaseboardFeatures {
type Target = u8;
fn deref(&self) -> &Self::Target {
&self.raw
}
}
impl From<u8> for BaseboardFeatures {
fn from(raw: u8) -> Self {
BaseboardFeatures { raw }
}
}
impl BaseboardFeatures {
pub fn hosting_board(&self) -> bool {
self.raw & 0x01 == 0x01
}
pub fn requires_daughterboard(&self) -> bool {
self.raw & 0x02 == 0x02
}
pub fn is_removable(&self) -> bool {
self.raw & 0x04 == 0x04
}
pub fn is_replaceable(&self) -> bool {
self.raw & 0x08 == 0x08
}
pub fn is_hot_swappable(&self) -> bool {
self.raw & 0x10 == 0x10
}
}
impl fmt::Debug for BaseboardFeatures {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct(std::any::type_name::<BaseboardFeatures>())
.field("raw", &self.raw)
.field("hosting_board", &self.hosting_board())
.field("requires_daughterboard", &self.requires_daughterboard())
.field("is_removable", &self.is_removable())
.field("is_replaceable", &self.is_replaceable())
.field("is_hot_swappable", &self.is_hot_swappable())
.finish()
}
}
pub struct ObjectHandleIterator<'a> {
data: &'a SMBiosBaseboardInformation<'a>,
current_index: usize,
current_entry: u8,
number_of_contained_object_handles: u8,
}
impl<'a> ObjectHandleIterator<'a> {
const OBJECT_HANDLES_OFFSET: usize = 0x0Fusize;
pub fn new(data: &'a SMBiosBaseboardInformation<'a>) -> Self {
ObjectHandleIterator {
data: data,
current_index: Self::OBJECT_HANDLES_OFFSET,
current_entry: 0,
number_of_contained_object_handles: data
.number_of_contained_object_handles()
.unwrap_or(0),
}
}
fn reset(&mut self) {
self.current_index = Self::OBJECT_HANDLES_OFFSET;
self.current_entry = 0;
}
}
impl<'a> IntoIterator for &'a ObjectHandleIterator<'a> {
type Item = Handle;
type IntoIter = ObjectHandleIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
ObjectHandleIterator {
data: self.data,
current_index: ObjectHandleIterator::OBJECT_HANDLES_OFFSET,
current_entry: 0,
number_of_contained_object_handles: self
.data
.number_of_contained_object_handles()
.unwrap_or(0),
}
}
}
impl<'a> Iterator for ObjectHandleIterator<'a> {
type Item = Handle;
fn next(&mut self) -> Option<Self::Item> {
if self.current_entry == self.number_of_contained_object_handles {
self.reset();
return None;
}
match self.data.parts().get_field_handle(self.current_index) {
Some(current_handle) => {
self.current_index = self.current_index + Handle::SIZE;
self.current_entry = self.current_entry + 1;
Some(current_handle)
}
None => {
self.reset();
None
}
}
}
}
impl<'a> fmt::Debug for ObjectHandleIterator<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_list().entries(self.into_iter()).finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_baseboard_information() {
let baseboard_information_bytes = vec![
0x02, 0x13, 0x10, 0x00,
0x01, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x0A, 0x02,
0x05, 0x00,
0x00, 0x12,
0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x43, 0x6F, 0x72, 0x70,
0x6F, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00,
0x53, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x20, 0x4C, 0x61, 0x70, 0x74, 0x6F, 0x70,
0x20, 0x33, 0x00,
0x42, 0x30, 0x30, 0x39, 0x32, 0x35, 0x30, 0x31, 0x30, 0x30, 0x4A, 0x31, 0x39, 0x33,
0x39, 0x42, 0x00,
0x00,
];
let parts = UndefinedStruct::new(&baseboard_information_bytes);
let baseboard_information = SMBiosBaseboardInformation::new(&parts);
assert_eq!(*baseboard_information.parts().header.handle(), 0x0010);
assert_eq!(baseboard_information.parts().header.length(), 0x13);
assert_eq!(
baseboard_information.manufacturer().unwrap(),
"Microsoft Corporation".to_string()
);
assert_eq!(
baseboard_information.product().unwrap(),
"Surface Laptop 3".to_string()
);
assert_eq!(baseboard_information.version().is_none(), true);
assert_eq!(
baseboard_information.serial_number().unwrap(),
"B009250100J1939B".to_string()
);
assert_eq!(baseboard_information.asset_tag().is_none(), true);
assert_eq!(
baseboard_information.feature_flags().unwrap(),
BaseboardFeatures::from(1)
);
assert_eq!(baseboard_information.location_in_chassis().is_none(), true);
assert_eq!(*baseboard_information.chassis_handle().unwrap(), 0x0F);
assert_eq!(
*baseboard_information.board_type().unwrap(),
BoardType::Motherboard
);
assert_eq!(
baseboard_information
.number_of_contained_object_handles()
.unwrap(),
2
);
let mut iterator = baseboard_information.contained_object_handle_iterator();
let first_entry = iterator.next().expect("has a first entry");
assert_eq!(*first_entry, 0x0005);
let second_entry = iterator.next().expect("has a second entry");
assert_eq!(*second_entry, 0x1200);
assert!(iterator.next().is_none());
let mut counter = 0;
for _entry in baseboard_information.contained_object_handle_iterator() {
counter = counter + 1;
}
assert_eq!(counter, 2);
println!("baseboard_information: {:?}", baseboard_information);
}
}