use crate::core::{strings::*, Handle, UndefinedStruct};
use crate::SMBiosStruct;
use serde::{ser::SerializeStruct, Serialize, Serializer};
use std::fmt;
use std::ops::Deref;
pub struct SMBiosStringProperty<'a> {
parts: &'a UndefinedStruct,
}
impl<'a> SMBiosStruct<'a> for SMBiosStringProperty<'a> {
const STRUCT_TYPE: u8 = 46u8;
fn new(parts: &'a UndefinedStruct) -> Self {
Self { parts }
}
fn parts(&self) -> &'a UndefinedStruct {
self.parts
}
}
impl<'a> SMBiosStringProperty<'a> {
pub fn string_property_id(&self) -> Option<StringPropertyIdData> {
self.parts
.get_field_word(0x04)
.map(|raw| StringPropertyIdData::from(raw))
}
pub fn string_property_value(&self) -> SMBiosString {
self.parts.get_field_string(0x06)
}
pub fn parent_handle(&self) -> Option<Handle> {
self.parts.get_field_handle(0x07)
}
}
impl fmt::Debug for SMBiosStringProperty<'_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct(std::any::type_name::<SMBiosStringProperty<'_>>())
.field("header", &self.parts.header)
.field("string_property_id", &self.string_property_id())
.field("string_property_value", &self.string_property_value())
.field("parent_handle", &self.parent_handle())
.finish()
}
}
impl Serialize for SMBiosStringProperty<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("SMBiosStringProperty", 3)?;
state.serialize_field("header", &self.parts.header)?;
state.serialize_field("string_property_id", &self.string_property_id())?;
state.serialize_field("string_property_value", &self.string_property_value())?;
state.serialize_field("parent_handle", &self.parent_handle())?;
state.end()
}
}
pub struct StringPropertyIdData {
pub raw: u16,
pub value: StringPropertyId,
}
impl fmt::Debug for StringPropertyIdData {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct(std::any::type_name::<StringPropertyIdData>())
.field("raw", &self.raw)
.field("value", &self.value)
.finish()
}
}
impl Serialize for StringPropertyIdData {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("StringPropertyIdData", 2)?;
state.serialize_field("raw", &self.raw)?;
state.serialize_field("value", &self.value)?;
state.end()
}
}
impl fmt::Display for StringPropertyIdData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.value {
StringPropertyId::None => write!(f, "{}", &self.raw),
_ => write!(f, "{:?}", &self.value),
}
}
}
impl Deref for StringPropertyIdData {
type Target = StringPropertyId;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl From<u16> for StringPropertyIdData {
fn from(raw: u16) -> Self {
StringPropertyIdData {
value: match raw {
0x0001 => StringPropertyId::UefiDevicePath,
_ => match raw & 0b1000_0000_0000_0000 {
0b1000_0000_0000_0000 => match raw & 0b1100_0000_0000_0000 {
0b1100_0000_0000_0000 => StringPropertyId::OemSpecific, _ => StringPropertyId::VendorSpecific, },
_ => StringPropertyId::None,
},
},
raw,
}
}
}
#[derive(Serialize, Debug, PartialEq, Eq)]
pub enum StringPropertyId {
UefiDevicePath,
VendorSpecific,
OemSpecific,
None,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unit_test() {
let struct_type46 = vec![
0x2E, 0x09, 0x10, 0x00,
0x01, 0x00, 0x01, 0x08, 0x00, b'A', b'b', b'c', b'd', 0x00, 0x00,
];
let parts = UndefinedStruct::new(&struct_type46);
let test_struct = SMBiosStringProperty::new(&parts);
assert_eq!(
test_struct.string_property_id().unwrap().value,
StringPropertyId::UefiDevicePath
);
assert_eq!(test_struct.string_property_value().to_string(), "Abcd");
assert_eq!(*test_struct.parent_handle().unwrap(), 8u16);
}
}