smbioslib/structs/types/
string_property.rs

1use crate::core::{strings::*, Handle, UndefinedStruct};
2use crate::SMBiosStruct;
3use serde::{ser::SerializeStruct, Serialize, Serializer};
4use std::fmt;
5use std::ops::Deref;
6
7/// # String Property (Type 46)
8///
9/// This structure defines a string property for another structure. This allows adding string properties that are
10/// common to several structures without having to modify the definitions of these structures. Multiple type 46
11/// structures can add string properties to the same parent structure.
12///
13/// NOTE: This structure type was added in version 3.5 of this specification.
14///
15/// Compliant with:
16/// DMTF SMBIOS Reference Specification 3.5.0 (DSP0134)
17/// Document Date: 2021-09-15
18pub struct SMBiosStringProperty<'a> {
19    parts: &'a UndefinedStruct,
20}
21
22impl<'a> SMBiosStruct<'a> for SMBiosStringProperty<'a> {
23    const STRUCT_TYPE: u8 = 46u8;
24
25    fn new(parts: &'a UndefinedStruct) -> Self {
26        Self { parts }
27    }
28
29    fn parts(&self) -> &'a UndefinedStruct {
30        self.parts
31    }
32}
33
34impl<'a> SMBiosStringProperty<'a> {
35    /// String Property Id
36    pub fn string_property_id(&self) -> Option<StringPropertyIdData> {
37        self.parts
38            .get_field_word(0x04)
39            .map(|raw| StringPropertyIdData::from(raw))
40    }
41
42    /// String Property Value
43    pub fn string_property_value(&self) -> SMBiosString {
44        self.parts.get_field_string(0x06)
45    }
46
47    /// Parent Handle
48    ///
49    /// Handle corresponding to the structure this string property applies to
50    pub fn parent_handle(&self) -> Option<Handle> {
51        self.parts.get_field_handle(0x07)
52    }
53}
54
55impl fmt::Debug for SMBiosStringProperty<'_> {
56    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
57        fmt.debug_struct(std::any::type_name::<SMBiosStringProperty<'_>>())
58            .field("header", &self.parts.header)
59            .field("string_property_id", &self.string_property_id())
60            .field("string_property_value", &self.string_property_value())
61            .field("parent_handle", &self.parent_handle())
62            .finish()
63    }
64}
65
66impl Serialize for SMBiosStringProperty<'_> {
67    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
68    where
69        S: Serializer,
70    {
71        let mut state = serializer.serialize_struct("SMBiosStringProperty", 3)?;
72        state.serialize_field("header", &self.parts.header)?;
73        state.serialize_field("string_property_id", &self.string_property_id())?;
74        state.serialize_field("string_property_value", &self.string_property_value())?;
75        state.serialize_field("parent_handle", &self.parent_handle())?;
76        state.end()
77    }
78}
79
80/// # String Property Id Data of [SMBiosStringProperty].
81pub struct StringPropertyIdData {
82    /// Raw value
83    ///
84    /// _raw_ is most useful when _value_ is None.
85    /// This is most likely to occur when the standard was updated but
86    /// this library code has not been updated to match the current
87    /// standard.
88    pub raw: u16,
89    /// The contained [StringPropertyId] value
90    pub value: StringPropertyId,
91}
92
93impl fmt::Debug for StringPropertyIdData {
94    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
95        fmt.debug_struct(std::any::type_name::<StringPropertyIdData>())
96            .field("raw", &self.raw)
97            .field("value", &self.value)
98            .finish()
99    }
100}
101
102impl Serialize for StringPropertyIdData {
103    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
104    where
105        S: Serializer,
106    {
107        let mut state = serializer.serialize_struct("StringPropertyIdData", 2)?;
108        state.serialize_field("raw", &self.raw)?;
109        state.serialize_field("value", &self.value)?;
110        state.end()
111    }
112}
113
114impl fmt::Display for StringPropertyIdData {
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116        match &self.value {
117            StringPropertyId::None => write!(f, "{}", &self.raw),
118            _ => write!(f, "{:?}", &self.value),
119        }
120    }
121}
122
123impl Deref for StringPropertyIdData {
124    type Target = StringPropertyId;
125
126    fn deref(&self) -> &Self::Target {
127        &self.value
128    }
129}
130
131impl From<u16> for StringPropertyIdData {
132    fn from(raw: u16) -> Self {
133        StringPropertyIdData {
134            value: match raw {
135                0x0001 => StringPropertyId::UefiDevicePath,
136                _ => match raw & 0b1000_0000_0000_0000 {
137                    // >= 32768 ?
138                    0b1000_0000_0000_0000 => match raw & 0b1100_0000_0000_0000 {
139                        // >= 49152 ?
140                        0b1100_0000_0000_0000 => StringPropertyId::OemSpecific, // 49152-65535
141                        _ => StringPropertyId::VendorSpecific,                  // 32768-49151
142                    },
143                    _ => StringPropertyId::None,
144                },
145            },
146            raw,
147        }
148    }
149}
150
151/// # String Property Id of [SMBiosStringProperty]
152#[derive(Serialize, Debug, PartialEq, Eq)]
153pub enum StringPropertyId {
154    /// UEFI Device Path
155    ///
156    /// String representation of a UEFI device path, as converted by
157    /// EFI_DEVICE_PATH_TO_TEXT_PROTOCOL. ConvertDevicePathToText() and then converted to UTF-8
158    UefiDevicePath,
159    /// Vendor Specific
160    VendorSpecific,
161    /// OEM Specific
162    OemSpecific,
163    /// A value unknown to this standard, check the raw value
164    None,
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170
171    #[test]
172    fn unit_test() {
173        let struct_type46 = vec![
174            // struct_type(46), length(0x09), handle(0x10)
175            0x2E, 0x09, 0x10, 0x00,
176            // string_property_id: (0x0001 - StringPropertyId::UefiDevicePath), string_property_value(1), parent_handle(0x0008)
177            0x01, 0x00, 0x01, 0x08, 0x00, //string_property_value: "Abcd"
178            b'A', b'b', b'c', b'd', 0x00, 0x00,
179        ];
180
181        let parts = UndefinedStruct::new(&struct_type46);
182        let test_struct = SMBiosStringProperty::new(&parts);
183
184        assert_eq!(
185            test_struct.string_property_id().unwrap().value,
186            StringPropertyId::UefiDevicePath
187        );
188
189        assert_eq!(test_struct.string_property_value().to_string(), "Abcd");
190
191        assert_eq!(*test_struct.parent_handle().unwrap(), 8u16);
192    }
193}