smbioslib/structs/types/
system_slot.rs

1use crate::core::{strings::*, UndefinedStruct};
2use crate::SMBiosStruct;
3use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer};
4use std::{convert::TryInto, fmt, ops::Deref};
5
6/// # System Slots (Type 9)
7///
8/// The information in this structure defines the attributes of a system slot. One
9/// structure is provided for each slot in the system.
10///
11/// Compliant with:
12/// DMTF SMBIOS Reference Specification 3.7.0 (DSP0134)
13/// Document Date: 2023-07-21
14pub struct SMBiosSystemSlot<'a> {
15    parts: &'a UndefinedStruct,
16}
17
18impl<'a> SMBiosStruct<'a> for SMBiosSystemSlot<'a> {
19    const STRUCT_TYPE: u8 = 9u8;
20
21    fn new(parts: &'a UndefinedStruct) -> Self {
22        Self { parts }
23    }
24
25    fn parts(&self) -> &'a UndefinedStruct {
26        self.parts
27    }
28}
29
30impl<'a> SMBiosSystemSlot<'a> {
31    /// Slot Designation
32    pub fn slot_designation(&self) -> SMBiosString {
33        self.parts.get_field_string(0x04)
34    }
35
36    /// Slot Type
37    pub fn system_slot_type(&self) -> Option<SystemSlotTypeData> {
38        self.parts
39            .get_field_byte(0x05)
40            .map(|raw| SystemSlotTypeData::from(raw))
41    }
42
43    /// Slot Data Bus Width
44    pub fn slot_data_bus_width(&self) -> Option<SlotWidthData> {
45        self.parts
46            .get_field_byte(0x06)
47            .map(|raw| SlotWidthData::from(raw))
48    }
49
50    /// Current Usage
51    pub fn current_usage(&self) -> Option<SlotCurrentUsageData> {
52        self.parts
53            .get_field_byte(0x07)
54            .map(|raw| SlotCurrentUsageData::from(raw))
55    }
56
57    /// Slot Length
58    pub fn slot_length(&self) -> Option<SlotLengthData> {
59        self.parts
60            .get_field_byte(0x08)
61            .map(|raw| SlotLengthData::from(raw))
62    }
63
64    /// Slot Id
65    pub fn slot_id(&self) -> Option<SystemSlotId> {
66        self.parts
67            .get_field_data(0x09, 0x0B)
68            .map(|id| SystemSlotId(id.try_into().unwrap()))
69    }
70
71    /// Slot Characteristics 1
72    pub fn slot_characteristics_1(&self) -> Option<SystemSlotCharacteristics1> {
73        self.parts
74            .get_field_byte(0x0B)
75            .map(|raw| SystemSlotCharacteristics1::from(raw))
76    }
77
78    /// Slot Characteristics 2
79    pub fn slot_characteristics_2(&self) -> Option<SystemSlotCharacteristics2> {
80        self.parts
81            .get_field_byte(0x0C)
82            .map(|raw| SystemSlotCharacteristics2::from(raw))
83    }
84
85    /// Segment Group Number (Base)
86    pub fn segment_group_number(&self) -> Option<SegmentGroupNumber> {
87        self.parts
88            .get_field_word(0x0D)
89            .map(|raw| SegmentGroupNumber::from(raw))
90    }
91
92    /// Bus Number (Base)
93    pub fn bus_number(&self) -> Option<BusNumber> {
94        self.parts
95            .get_field_byte(0x0F)
96            .map(|raw| BusNumber::from(raw))
97    }
98
99    /// Device/Function Number (Base)
100    pub fn device_function_number(&self) -> Option<DeviceFunctionNumber> {
101        self.parts
102            .get_field_byte(0x10)
103            .map(|raw| DeviceFunctionNumber::from(raw))
104    }
105
106    /// Data Bus Width (Base)
107    pub fn data_bus_width(&self) -> Option<u8> {
108        self.parts.get_field_byte(0x11)
109    }
110
111    /// Number of peer Segment/Bus/Device/Function/Width groups that follow
112    pub fn peer_group_count(&self) -> Option<usize> {
113        self.parts
114            .get_field_byte(0x12)
115            .and_then(|count| Some(count as usize))
116    }
117
118    /// 5*n
119    fn peer_group_size(&self) -> Option<usize> {
120        self.peer_group_count()
121            .and_then(|count| Some(count as usize * SlotPeerGroup::SIZE))
122    }
123
124    /// Iterates over the [SlotPeerGroup] entries
125    pub fn peer_group_iterator(&'a self) -> SlotPeerGroupIterator<'a> {
126        SlotPeerGroupIterator::new(self)
127    }
128
129    /// Slot Information
130    pub fn slot_information(&self) -> Option<u8> {
131        self.peer_group_size()
132            .and_then(|size| self.parts.get_field_byte(size + 0x13))
133    }
134
135    /// Slot Physical Width
136    ///
137    /// This field indicates the physical width of the slot whereas _slot_data_bus_width()_ indicates the
138    /// electrical width of the slot.
139    ///
140    /// The possible values of both fields are listed in Table 46 – System Slots: Slot Width field.
141    pub fn slot_physical_width(&self) -> Option<SlotWidthData> {
142        self.peer_group_size().and_then(|size| {
143            self.parts
144                .get_field_byte(size + 0x14)
145                .map(|raw| SlotWidthData::from(raw))
146        })
147    }
148
149    /// Slot Pitch
150    ///
151    /// The Slot Pitch field contains a numeric value that indicates the pitch of the slot in units of 1/100 millimeter.
152    ///
153    /// The pitch is defined by each slot/card specification, but typically describes add-in card to add-in card
154    /// pitch.
155    ///
156    /// For EDSFF slots, the pitch is defined in SFF-TA-1006 table 7.1, SFF-TA-1007 table 7.1 (add-in card to
157    /// add-in card pitch), and SFF-TA-1008 table 6-1 (SSD to SSD pitch).
158    ///
159    /// For example, if the pitch for the slot is 12.5 mm, the value 1250 would be used.
160    ///
161    /// A value of 0 implies that the slot pitch is not given or is unknown.
162    pub fn slot_pitch(&self) -> Option<u16> {
163        self.peer_group_size()
164            .and_then(|size| self.parts.get_field_word(size + 0x15))
165    }
166
167    /// Slot Height
168    ///
169    /// This field indicates the maximum supported card height for the slot.
170    ///
171    /// Available in version 3.5.0 and later.
172    pub fn slot_height(&self) -> Option<SlotHeightData> {
173        self.peer_group_size().and_then(|size| {
174            self.parts
175                .get_field_byte(size + 0x17)
176                .map(|raw| SlotHeightData::from(raw))
177        })
178    }
179}
180
181impl fmt::Debug for SMBiosSystemSlot<'_> {
182    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
183        fmt.debug_struct(std::any::type_name::<SMBiosSystemSlot<'_>>())
184            .field("header", &self.parts.header)
185            .field("slot_designation", &self.slot_designation())
186            .field("system_slot_type", &self.system_slot_type())
187            .field("slot_data_bus_width", &self.slot_data_bus_width())
188            .field("current_usage", &self.current_usage())
189            .field("slot_length", &self.slot_length())
190            .field("slot_id", &self.slot_id())
191            .field("slot_characteristics_1", &self.slot_characteristics_1())
192            .field("slot_characteristics_2", &self.slot_characteristics_2())
193            .field("segment_group_number", &self.segment_group_number())
194            .field("bus_number", &self.bus_number())
195            .field("device_function_number", &self.device_function_number())
196            .field("data_bus_width", &self.data_bus_width())
197            .field("peer_group_count", &self.peer_group_count())
198            .field("peer_group_iterator", &self.peer_group_iterator())
199            .field("slot_information", &self.slot_information())
200            .field("slot_physical_width", &self.slot_physical_width())
201            .field("slot_pitch", &self.slot_pitch())
202            .finish()
203    }
204}
205
206impl Serialize for SMBiosSystemSlot<'_> {
207    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
208    where
209        S: Serializer,
210    {
211        let mut state = serializer.serialize_struct("SMBiosSystemSlot", 18)?;
212        state.serialize_field("header", &self.parts.header)?;
213        state.serialize_field("slot_designation", &self.slot_designation())?;
214        state.serialize_field("system_slot_type", &self.system_slot_type())?;
215        state.serialize_field("slot_data_bus_width", &self.slot_data_bus_width())?;
216        state.serialize_field("current_usage", &self.current_usage())?;
217        state.serialize_field("slot_length", &self.slot_length())?;
218        state.serialize_field("slot_id", &self.slot_id())?;
219        state.serialize_field("slot_characteristics_1", &self.slot_characteristics_1())?;
220        state.serialize_field("slot_characteristics_2", &self.slot_characteristics_2())?;
221        state.serialize_field("segment_group_number", &self.segment_group_number())?;
222        state.serialize_field("bus_number", &self.bus_number())?;
223        state.serialize_field("device_function_number", &self.device_function_number())?;
224        state.serialize_field("data_bus_width", &self.data_bus_width())?;
225        state.serialize_field("peer_group_count", &self.peer_group_count())?;
226        state.serialize_field("peer_group_iterator", &self.peer_group_iterator())?;
227        state.serialize_field("slot_information", &self.slot_information())?;
228        state.serialize_field("slot_physical_width", &self.slot_physical_width())?;
229        state.serialize_field("slot_pitch", &self.slot_pitch())?;
230        state.end()
231    }
232}
233
234/// # System Slots - Slot Id
235///
236/// The Slot ID field of the System Slot structure provides a mechanism to correlate the physical attributes of
237/// the slot to its logical access method (which varies based on the Slot Type field). The Slot ID field has
238/// meaning only for the slot types described in the table:
239///
240/// | Slot Type | Slot ID Field Meaning |
241/// | --------- | --------------------- |
242/// | MCA | Identifies the logical Micro Channel slot number, in the range 1 to 15, in byte 0. Byte 1 is set to 0. |
243/// | PCI, AGP, PCIX, PCI Express | On a system that supports ACPI, identifies the value returned in the _SUN object for this slot. On a system that supports the PCI IRQ Routing Table Specification, identifies the value present in the Slot Number field of the PCI Interrupt Routing table entry that is associated with this slot, in byte 0 - byte 1 is set to 0. The table is returned by the "Get PCI Interrupt Routing Options" PCI BIOS function call and provided directly in the PCI IRQ Routing Table Specification ($PIRQ). Software can determine the PCI bus number and device associated with the slot by matching the "Slot ID" to an entry in the routing-table and ultimately determine what device is present in that slot. NOTE: This definition also applies to the 66 MHz-capable PCI slots. |
244/// | PCMCIA | Identifies the Adapter Number (byte 0) and Socket Number (byte 1) to be passed toPCMCIA Socket Services to identify this slot |
245#[derive(Serialize, Debug, PartialEq, Eq, Clone, Copy)]
246pub struct SystemSlotId(pub [u8; 2]);
247
248impl Deref for SystemSlotId {
249    type Target = [u8; 2];
250
251    fn deref(&self) -> &Self::Target {
252        &self.0
253    }
254}
255
256impl SystemSlotId {
257    /// The first system slot Id byte (found at offset 09h).
258    pub fn byte_0(&self) -> u8 {
259        self.0[0]
260    }
261
262    /// The second system slot Id byte (found at offset 0Ah).
263    pub fn byte_1(&self) -> u8 {
264        self.0[1]
265    }
266}
267
268/// # System Slot Type Data
269pub struct SystemSlotTypeData {
270    /// Raw value
271    ///
272    /// _raw_ is most useful when _value_ is None.
273    /// This is most likely to occur when the standard was updated but
274    /// this library code has not been updated to match the current
275    /// standard.
276    pub raw: u8,
277    /// The contained [SystemSlotType] value
278    pub value: SystemSlotType,
279}
280
281impl Deref for SystemSlotTypeData {
282    type Target = SystemSlotType;
283
284    fn deref(&self) -> &Self::Target {
285        &self.value
286    }
287}
288
289impl From<u8> for SystemSlotTypeData {
290    /// System Slot Type
291    fn from(raw: u8) -> Self {
292        use M2SlotType::*;
293        use MXMSlotType::*;
294        use PciExpressGeneration::*;
295        use PciExpressSlotWidth::*;
296        use SystemSlotType::*;
297        SystemSlotTypeData {
298            value: match raw {
299                0x01 => Other,
300                0x02 => Unknown,
301                0x03 => Isa,
302                0x04 => Mca,
303                0x05 => Eisa,
304                0x06 => Pci,
305                0x07 => Pcmcia,
306                0x08 => VlVesa,
307                0x09 => Proprietary,
308                0x0A => ProcessorCardSlot,
309                0x0B => ProprietaryMemoryCardSlot,
310                0x0C => IORiserCardSlot,
311                0x0D => NuBus,
312                0x0E => Pci66MhzCapable,
313                0x0F => Agp(AgpSlotWidth::X1),
314                0x10 => Agp(AgpSlotWidth::X2),
315                0x11 => Agp(AgpSlotWidth::X4),
316                0x12 => PciX,
317                0x13 => Agp(AgpSlotWidth::X8),
318                0x14 => M2(M2Socket1DP),
319                0x15 => M2(M2Socket1SD),
320                0x16 => M2(M2Socket2),
321                0x17 => M2(M2Socket3),
322                0x18 => Mxm(MxmTypeI),
323                0x19 => Mxm(MxmTypeII),
324                0x1A => Mxm(MxmTypeIIIStandard),
325                0x1B => Mxm(MxmTypeIIIHE),
326                0x1C => Mxm(MxmTypeIV),
327                0x1D => Mxm(Mxm3TypeA),
328                0x1E => Mxm(Mxm3TypeB),
329                0x1F => PciExpress(PCIExpressGen2, Sff8639),
330                0x20 => PciExpress(PCIExpressGen3, Sff8639),
331                0x21 => PciExpress(Undefined, PciExpressMini52WithKeepouts),
332                0x22 => PciExpress(Undefined, PciExpressMini52WithoutKeepouts),
333                0x23 => PciExpress(Undefined, PciExpressMini76),
334                0x24 => PciExpress(PCIExpressGen4, Sff8639),
335                0x25 => PciExpress(PCIExpressGen5, Sff8639),
336                0x26 => OcpNic30SmallFormFactor,
337                0x27 => OcpNic30LargeFormFactor,
338                0x28 => OcpNicPriorTo30,
339                0x30 => CxlFlexbus1,
340                0xA0 => PC98C20,
341                0xA1 => PC98C24,
342                0xA2 => PC98E,
343                0xA3 => PC98LocalBus,
344                0xA4 => PC98Card,
345                0xA5 => PciExpress(PCIExpressGen1, UndefinedSlotWidth),
346                0xA6 => PciExpress(PCIExpressGen1, X1),
347                0xA7 => PciExpress(PCIExpressGen1, X2),
348                0xA8 => PciExpress(PCIExpressGen1, X4),
349                0xA9 => PciExpress(PCIExpressGen1, X8),
350                0xAA => PciExpress(PCIExpressGen1, X16),
351                0xAB => PciExpress(PCIExpressGen2, UndefinedSlotWidth),
352                0xAC => PciExpress(PCIExpressGen2, X1),
353                0xAD => PciExpress(PCIExpressGen2, X2),
354                0xAE => PciExpress(PCIExpressGen2, X4),
355                0xAF => PciExpress(PCIExpressGen2, X8),
356                0xB0 => PciExpress(PCIExpressGen2, X16),
357                0xB1 => PciExpress(PCIExpressGen3, UndefinedSlotWidth),
358                0xB2 => PciExpress(PCIExpressGen3, X1),
359                0xB3 => PciExpress(PCIExpressGen3, X2),
360                0xB4 => PciExpress(PCIExpressGen3, X4),
361                0xB5 => PciExpress(PCIExpressGen3, X8),
362                0xB6 => PciExpress(PCIExpressGen3, X16),
363                0xB8 => PciExpress(PCIExpressGen4, UndefinedSlotWidth),
364                0xB9 => PciExpress(PCIExpressGen4, X1),
365                0xBA => PciExpress(PCIExpressGen4, X2),
366                0xBB => PciExpress(PCIExpressGen4, X4),
367                0xBC => PciExpress(PCIExpressGen4, X8),
368                0xBD => PciExpress(PCIExpressGen4, X16),
369                0xBE => PciExpress(PCIExpressGen5, UndefinedSlotWidth),
370                0xBF => PciExpress(PCIExpressGen5, X1),
371                0xC0 => PciExpress(PCIExpressGen5, X2),
372                0xC1 => PciExpress(PCIExpressGen5, X4),
373                0xC2 => PciExpress(PCIExpressGen5, X8),
374                0xC3 => PciExpress(PCIExpressGen5, X16),
375                0xC4 => PciExpress(PCIExpressGen6, UndefinedSlotWidth),
376                0xC5 => EnterpriseAndDataCenter1UE1,
377                0xC6 => EnterpriseAndDataCenter3InE3,
378                _ => None,
379            },
380            raw,
381        }
382    }
383}
384
385impl fmt::Debug for SystemSlotTypeData {
386    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
387        fmt.debug_struct(std::any::type_name::<SystemSlotTypeData>())
388            .field("raw", &self.raw)
389            .field("value", &self.value)
390            .finish()
391    }
392}
393
394impl Serialize for SystemSlotTypeData {
395    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
396    where
397        S: Serializer,
398    {
399        let mut state = serializer.serialize_struct("SystemSlotTypeData", 2)?;
400        state.serialize_field("raw", &self.raw)?;
401        state.serialize_field("value", &self.value)?;
402        state.end()
403    }
404}
405
406impl fmt::Display for SystemSlotTypeData {
407    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
408        match &self.value {
409            SystemSlotType::None => write!(f, "{}", &self.raw),
410            _ => write!(f, "{:?}", &self.value),
411        }
412    }
413}
414
415/// # System Slot Type
416#[derive(Serialize, Debug, PartialEq, Eq)]
417pub enum SystemSlotType {
418    /// Other
419    Other,
420    /// Unknown
421    Unknown,
422    /// ISA
423    Isa,
424    /// MCA
425    Mca,
426    /// EISA
427    Eisa,
428    /// PCI
429    Pci,
430    /// PC Card (PCMCIA)
431    Pcmcia,
432    /// VL-VESA
433    VlVesa,
434    /// Proprietary
435    Proprietary,
436    /// Processor Card Slot
437    ProcessorCardSlot,
438    /// Proprietary Memory Card Slot
439    ProprietaryMemoryCardSlot,
440    /// I/O Riser Card Slot
441    IORiserCardSlot,
442    /// NuBus
443    NuBus,
444    /// PCI – 66MHz Capable
445    Pci66MhzCapable,
446    /// AGP
447    Agp(AgpSlotWidth),
448    /// MXM
449    Mxm(MXMSlotType),
450    /// PCI-X
451    PciX,
452    /// M.2
453    M2(M2SlotType),
454    /// OCP NIC 3.0 Small Form Factor (SFF)
455    OcpNic30SmallFormFactor,
456    /// OCP NIC 3.0 Large Form Factor (LFF)
457    OcpNic30LargeFormFactor,
458    /// OCP NIC Prior to 3.0
459    OcpNicPriorTo30,
460    /// CXL Flexbus 1.0 (deprecated, see note below)
461    CxlFlexbus1,
462    /// PC-98/C20
463    PC98C20,
464    /// PC-98/C24
465    PC98C24,
466    /// PC-98/E
467    PC98E,
468    /// PC-98/Local Bus
469    PC98LocalBus,
470    /// PC-98/Card
471    PC98Card,
472    /// PCI Express
473    PciExpress(PciExpressGeneration, PciExpressSlotWidth),
474    /// Enterprise and Datacenter 1U E1 Form Factor Slot (EDSFF E1.S, E1.L) E1 slot length is reported in Slot Length field (see section 7.10.4). E1 slot pitch is reported in Slot Pitch field (see section 7.10.12). See specifications SFF-TA-1006 and SFF-TA-1007 for more details on values for slot length and pitch.
475    EnterpriseAndDataCenter1UE1,
476    /// Enterprise and Datacenter 3" E3 Form Factor Slot (EDSFF E3.S, E3.L) E3 slot length is reported in Slot Length field (see section 7.10.4). E3 slot pitch is reported in Slot Pitch field (see section 7.10.12). See specification SFF-TA-1008 for details on values for slot length and pitch.
477    EnterpriseAndDataCenter3InE3,
478    /// A value unknown to this standard, check the raw value
479    None,
480}
481
482/// The generation of PciExpress used by the slot.
483#[derive(Serialize, Debug, PartialEq, Eq)]
484pub enum PciExpressGeneration {
485    /// PCI Express Gen 1
486    PCIExpressGen1,
487    /// PCI Express Gen 2
488    PCIExpressGen2,
489    /// PCI Express Gen 3
490    PCIExpressGen3,
491    /// PCI Express Gen 4
492    PCIExpressGen4,
493    /// PCI Express Gen 5
494    PCIExpressGen5,
495    /// PCI Express Gen 6 and Beyond
496    PCIExpressGen6,
497    /// Undefined
498    Undefined,
499}
500
501/// The slot width of a PCI Express slot specified in the SystemSlotType
502#[derive(Serialize, Debug, PartialEq, Eq)]
503pub enum PciExpressSlotWidth {
504    /// An undefined slot width
505    UndefinedSlotWidth,
506    /// X1
507    X1,
508    /// X2
509    X2,
510    /// X4
511    X4,
512    /// X8
513    X8,
514    /// X16
515    X16,
516    /// Small form factor 639
517    Sff8639,
518    /// PCI Express Mini 52-pin (CEM spec. 2.0) with bottom-side keep-outs. Use Slot Length field value 03h (short length) for "half-Mini card" -only support, 04h (long length) for "full-Mini card" or dual support.
519    PciExpressMini52WithKeepouts,
520    /// PCI Express Mini 52-pin (CEM spec. 2.0) without bottom-side keep-outs. Use Slot Length field value 03h (short length) for "half-Mini card" -only support, 04h (long length) for "full-Mini card" or dual support.
521    PciExpressMini52WithoutKeepouts,
522    /// PCI Express Mini 76-pin (CEM spec. 2.0) Corresponds to Display-Mini card.
523    PciExpressMini76,
524}
525
526/// The slot width of an AGP slot specified in the SystemSlotType
527#[derive(Serialize, Debug, PartialEq, Eq)]
528pub enum AgpSlotWidth {
529    /// X1
530    X1,
531    /// X2
532    X2,
533    /// X4
534    X4,
535    /// X8
536    X8,
537}
538
539/// An MXM SlotType
540#[derive(Serialize, Debug, PartialEq, Eq)]
541pub enum MXMSlotType {
542    /// MXM Type I
543    MxmTypeI,
544    /// MXM Type II
545    MxmTypeII,
546    /// MXM Type III (standard connector)
547    MxmTypeIIIStandard,
548    /// MXM Type III (HE connector)
549    MxmTypeIIIHE,
550    /// MXM Type IV
551    MxmTypeIV,
552    /// MXM 3.0 Type A
553    Mxm3TypeA,
554    /// MXM 3.0 Type B
555    Mxm3TypeB,
556}
557
558/// An M.2 SlotType
559#[derive(Serialize, Debug, PartialEq, Eq)]
560pub enum M2SlotType {
561    /// M.2 Socket 1-DP (Mechanical Key A)
562    M2Socket1DP,
563    /// M.2 Socket 1-SD (Mechanical Key E)
564    M2Socket1SD,
565    /// M.2 Socket 2 (Mechanical Key B)
566    M2Socket2,
567    /// M.2 Socket 3 (Mechanical Key M)
568    M2Socket3,
569}
570
571/// # Data Bus Width Data
572pub struct SlotWidthData {
573    /// Raw value
574    ///
575    /// _raw_ is most useful when _value_ is None.
576    /// This is most likely to occur when the standard was updated but
577    /// this library code has not been updated to match the current
578    /// standard.
579    pub raw: u8,
580    /// The contained [SlotWidth] value
581    pub value: SlotWidth,
582}
583
584impl Deref for SlotWidthData {
585    type Target = SlotWidth;
586
587    fn deref(&self) -> &Self::Target {
588        &self.value
589    }
590}
591
592impl From<u8> for SlotWidthData {
593    fn from(raw: u8) -> Self {
594        SlotWidthData {
595            value: match raw {
596                0x01 => SlotWidth::Other,
597                0x02 => SlotWidth::Unknown,
598                0x03 => SlotWidth::Bit8,
599                0x04 => SlotWidth::Bit16,
600                0x05 => SlotWidth::Bit32,
601                0x06 => SlotWidth::Bit64,
602                0x07 => SlotWidth::Bit128,
603                0x08 => SlotWidth::X1,
604                0x09 => SlotWidth::X2,
605                0x0A => SlotWidth::X4,
606                0x0B => SlotWidth::X8,
607                0x0C => SlotWidth::X12,
608                0x0D => SlotWidth::X16,
609                0x0E => SlotWidth::X32,
610                _ => SlotWidth::None,
611            },
612            raw,
613        }
614    }
615}
616
617impl fmt::Debug for SlotWidthData {
618    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
619        fmt.debug_struct(std::any::type_name::<SlotWidthData>())
620            .field("raw", &self.raw)
621            .field("value", &self.value)
622            .finish()
623    }
624}
625
626impl Serialize for SlotWidthData {
627    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
628    where
629        S: Serializer,
630    {
631        let mut state = serializer.serialize_struct("SlotWidthData", 2)?;
632        state.serialize_field("raw", &self.raw)?;
633        state.serialize_field("value", &self.value)?;
634        state.end()
635    }
636}
637
638/// # Slot Width
639#[derive(Serialize, Debug, PartialEq, Eq)]
640pub enum SlotWidth {
641    /// Other
642    Other,
643    /// Unknown
644    Unknown,
645    /// 8 bit
646    Bit8,
647    /// 16 bit
648    Bit16,
649    /// 32 bit
650    Bit32,
651    /// 64 bit
652    Bit64,
653    /// 128 bit
654    Bit128,
655    /// 1x or x1
656    X1,
657    /// 2x or x2
658    X2,
659    /// 4x or x4
660    X4,
661    /// 8x or x8
662    X8,
663    /// 12x or x12
664    X12,
665    /// 16x or x16
666    X16,
667    /// 32x or x32
668    X32,
669    /// A value unknown to this standard, check the raw value
670    None,
671}
672
673/// # Slot Height Data
674pub struct SlotHeightData {
675    /// Raw value
676    ///
677    /// _raw_ is most useful when _value_ is None.
678    /// This is most likely to occur when the standard was updated but
679    /// this library code has not been updated to match the current
680    /// standard.
681    pub raw: u8,
682    /// The contained [SlotHeight] value
683    pub value: SlotHeight,
684}
685
686impl Deref for SlotHeightData {
687    type Target = SlotHeight;
688
689    fn deref(&self) -> &Self::Target {
690        &self.value
691    }
692}
693
694impl From<u8> for SlotHeightData {
695    fn from(raw: u8) -> Self {
696        SlotHeightData {
697            value: match raw {
698                0x00 => SlotHeight::NotApplicable,
699                0x01 => SlotHeight::Other,
700                0x02 => SlotHeight::Unknown,
701                0x03 => SlotHeight::FullHeight,
702                0x04 => SlotHeight::LowProfile,
703                _ => SlotHeight::None,
704            },
705            raw,
706        }
707    }
708}
709
710impl fmt::Debug for SlotHeightData {
711    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
712        fmt.debug_struct(std::any::type_name::<SlotHeightData>())
713            .field("raw", &self.raw)
714            .field("value", &self.value)
715            .finish()
716    }
717}
718
719impl Serialize for SlotHeightData {
720    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
721    where
722        S: Serializer,
723    {
724        let mut state = serializer.serialize_struct("SlotHeightData", 2)?;
725        state.serialize_field("raw", &self.raw)?;
726        state.serialize_field("value", &self.value)?;
727        state.end()
728    }
729}
730
731/// # Slot Height
732#[derive(Serialize, Debug, PartialEq, Eq)]
733pub enum SlotHeight {
734    /// Not Applicable
735    NotApplicable,
736    /// Other
737    Other,
738    /// Unknown
739    Unknown,
740    /// Full Height
741    FullHeight,
742    /// Low-profile
743    LowProfile,
744    /// A value unknown to this standard, check the raw value
745    None,
746}
747
748/// # System Slot Current Usage Data
749pub struct SlotCurrentUsageData {
750    /// Raw value
751    ///
752    /// _raw_ is most useful when _value_ is None.
753    /// This is most likely to occur when the standard was updated but
754    /// this library code has not been updated to match the current
755    /// standard.
756    pub raw: u8,
757    /// The contained [SlotCurrentUsage] value
758    pub value: SlotCurrentUsage,
759}
760
761impl Deref for SlotCurrentUsageData {
762    type Target = SlotCurrentUsage;
763
764    fn deref(&self) -> &Self::Target {
765        &self.value
766    }
767}
768
769impl From<u8> for SlotCurrentUsageData {
770    fn from(raw: u8) -> Self {
771        SlotCurrentUsageData {
772            value: match raw {
773                0x01 => SlotCurrentUsage::Other,
774                0x02 => SlotCurrentUsage::Unknown,
775                0x03 => SlotCurrentUsage::Available,
776                0x04 => SlotCurrentUsage::InUse,
777                0x05 => SlotCurrentUsage::Unavailable,
778                _ => SlotCurrentUsage::None,
779            },
780            raw,
781        }
782    }
783}
784
785impl fmt::Debug for SlotCurrentUsageData {
786    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
787        fmt.debug_struct(std::any::type_name::<SlotCurrentUsageData>())
788            .field("raw", &self.raw)
789            .field("value", &self.value)
790            .finish()
791    }
792}
793
794impl Serialize for SlotCurrentUsageData {
795    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
796    where
797        S: Serializer,
798    {
799        let mut state = serializer.serialize_struct("SlotCurrentUsageData", 2)?;
800        state.serialize_field("raw", &self.raw)?;
801        state.serialize_field("value", &self.value)?;
802        state.end()
803    }
804}
805
806/// # System Slot Current Usage
807#[derive(Serialize, Debug, PartialEq, Eq)]
808pub enum SlotCurrentUsage {
809    /// Other
810    Other,
811    /// Unknown
812    Unknown,
813    /// Available
814    Available,
815    /// In use
816    InUse,
817    /// Unavailable
818    Unavailable,
819    /// A value unknown to this standard, check the raw value
820    None,
821}
822
823/// # System Slot Current Usage Data
824pub struct SlotLengthData {
825    /// Raw value
826    ///
827    /// _raw_ is most useful when _value_ is None.
828    /// This is most likely to occur when the standard was updated but
829    /// this library code has not been updated to match the current
830    /// standard.
831    pub raw: u8,
832    /// The contained [SlotLength] value
833    pub value: SlotLength,
834}
835
836impl Deref for SlotLengthData {
837    type Target = SlotLength;
838
839    fn deref(&self) -> &Self::Target {
840        &self.value
841    }
842}
843
844impl From<u8> for SlotLengthData {
845    fn from(raw: u8) -> Self {
846        use SlotLength::*;
847        SlotLengthData {
848            value: match raw {
849                0x01 => Other,
850                0x02 => Unknown,
851                0x03 => ShortLength,
852                0x04 => LongLength,
853                0x05 => DriveFormFactor25,
854                0x06 => DriveFormFactor35,
855                _ => None,
856            },
857            raw,
858        }
859    }
860}
861
862impl fmt::Debug for SlotLengthData {
863    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
864        fmt.debug_struct(std::any::type_name::<SlotLengthData>())
865            .field("raw", &self.raw)
866            .field("value", &self.value)
867            .finish()
868    }
869}
870
871impl Serialize for SlotLengthData {
872    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
873    where
874        S: Serializer,
875    {
876        let mut state = serializer.serialize_struct("SlotLengthData", 2)?;
877        state.serialize_field("raw", &self.raw)?;
878        state.serialize_field("value", &self.value)?;
879        state.end()
880    }
881}
882
883/// # System Slot Length
884#[derive(Serialize, Debug, PartialEq, Eq)]
885pub enum SlotLength {
886    /// Other
887    Other,
888    /// Unknown
889    Unknown,
890    /// Short Length
891    ShortLength,
892    /// Long Length
893    LongLength,
894    /// 2.5" drive form factor
895    DriveFormFactor25,
896    /// 3.5" drive form factor
897    DriveFormFactor35,
898    /// A value unknown to this standard, check the raw value
899    None,
900}
901
902/// # System Slot Characteristics 1
903#[derive(PartialEq, Eq)]
904pub struct SystemSlotCharacteristics1 {
905    /// Raw value
906    ///
907    /// _raw_ is useful for masked comparisons.
908    pub raw: u8,
909}
910
911impl Deref for SystemSlotCharacteristics1 {
912    type Target = u8;
913
914    fn deref(&self) -> &Self::Target {
915        &self.raw
916    }
917}
918
919impl From<u8> for SystemSlotCharacteristics1 {
920    fn from(raw: u8) -> Self {
921        SystemSlotCharacteristics1 { raw }
922    }
923}
924
925impl SystemSlotCharacteristics1 {
926    /// Characteristics unknown.
927    pub fn unknown(&self) -> bool {
928        self.raw & 0x01 == 0x01
929    }
930
931    /// Provides 5.0 volts.
932    pub fn provides5_volts(&self) -> bool {
933        self.raw & 0x02 == 0x02
934    }
935
936    /// Provides 3.3 volts.
937    pub fn provides33_volts(&self) -> bool {
938        self.raw & 0x04 == 0x04
939    }
940
941    /// Slot’s opening is shared with another slot (for example, PCI/EISA shared slot).
942    pub fn shared(&self) -> bool {
943        self.raw & 0x08 == 0x08
944    }
945
946    /// PC Card slot supports PC Card-16.
947    pub fn supports_pc_card16(&self) -> bool {
948        self.raw & 0x10 == 0x10
949    }
950
951    /// PC Card slot supports CardBus.
952    pub fn supports_card_bus(&self) -> bool {
953        self.raw & 0x20 == 0x20
954    }
955
956    /// PC Card slot supports Zoom Video.
957    pub fn supports_zoom_video(&self) -> bool {
958        self.raw & 0x40 == 0x40
959    }
960
961    /// PC Card slot supports Modem Ring Resume.
962    pub fn supports_modem_ring_resume(&self) -> bool {
963        self.raw & 0x80 == 0x80
964    }
965}
966
967impl fmt::Debug for SystemSlotCharacteristics1 {
968    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
969        fmt.debug_struct(std::any::type_name::<SystemSlotCharacteristics1>())
970            .field("raw", &self.raw)
971            .field("unknown", &self.unknown())
972            .field("provides5_volts", &self.provides5_volts())
973            .field("provides33_volts", &self.provides33_volts())
974            .field("shared", &self.shared())
975            .field("supports_pc_card16", &self.supports_pc_card16())
976            .field("supports_card_bus", &self.supports_card_bus())
977            .field("supports_zoom_video", &self.supports_zoom_video())
978            .field(
979                "supports_modem_ring_resume",
980                &self.supports_modem_ring_resume(),
981            )
982            .finish()
983    }
984}
985
986impl Serialize for SystemSlotCharacteristics1 {
987    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
988    where
989        S: Serializer,
990    {
991        let mut state = serializer.serialize_struct("SystemSlotCharacteristics1", 9)?;
992        state.serialize_field("raw", &self.raw)?;
993        state.serialize_field("unknown", &self.unknown())?;
994        state.serialize_field("provides5_volts", &self.provides5_volts())?;
995        state.serialize_field("provides33_volts", &self.provides33_volts())?;
996        state.serialize_field("shared", &self.shared())?;
997        state.serialize_field("supports_pc_card16", &self.supports_pc_card16())?;
998        state.serialize_field("supports_card_bus", &self.supports_card_bus())?;
999        state.serialize_field("supports_zoom_video", &self.supports_zoom_video())?;
1000        state.serialize_field(
1001            "supports_modem_ring_resume",
1002            &self.supports_modem_ring_resume(),
1003        )?;
1004        state.end()
1005    }
1006}
1007
1008/// # System Slot Characteristics 2
1009#[derive(PartialEq, Eq)]
1010pub struct SystemSlotCharacteristics2 {
1011    /// Raw value
1012    ///
1013    /// _raw_ is useful when there are values not yet defiend.
1014    /// This is most likely to occur when the standard was updated but
1015    /// this library code has not been updated to match the current
1016    /// standard.
1017    pub raw: u8,
1018}
1019
1020impl Deref for SystemSlotCharacteristics2 {
1021    type Target = u8;
1022
1023    fn deref(&self) -> &Self::Target {
1024        &self.raw
1025    }
1026}
1027
1028impl From<u8> for SystemSlotCharacteristics2 {
1029    fn from(raw: u8) -> Self {
1030        SystemSlotCharacteristics2 { raw }
1031    }
1032}
1033
1034impl SystemSlotCharacteristics2 {
1035    /// PCI slot supports Power Management Event (PME#) signal.
1036    pub fn supports_power_management_event(&self) -> bool {
1037        self.raw & 0x01 == 0x01
1038    }
1039
1040    /// Slot supports hot-plug devices.
1041    pub fn supports_hot_plug_devices(&self) -> bool {
1042        self.raw & 0x02 == 0x02
1043    }
1044
1045    /// PCI slot supports SMBus signal.
1046    pub fn supports_smbus_signal(&self) -> bool {
1047        self.raw & 0x04 == 0x04
1048    }
1049
1050    /// PCIe slot supports bifurcation.
1051    ///
1052    /// This slot can partition its lanes into two or more PCIe devices plugged into the slot.
1053    /// Note: This field does not indicate complete details on what levels of bifurcation
1054    /// are supported by the slot, but only that the slot supports some level of bifurcation.
1055    pub fn supports_bifurcation(&self) -> bool {
1056        self.raw & 0x08 == 0x08
1057    }
1058
1059    /// Slot supports async/surprise removal.
1060    ///
1061    /// i.e., removal without prior notification to the operating system, device driver, or applications.
1062    pub fn supports_suprise_removal(&self) -> bool {
1063        self.raw & 0x10 == 0x10
1064    }
1065
1066    /// Flexbus slot, CXL 1.0 capable.
1067    pub fn flexbus_slot_cxl10_capable(&self) -> bool {
1068        self.raw & 0x20 == 0x20
1069    }
1070
1071    /// Flexbus slot, CXL 2.0 capable.
1072    pub fn flexbus_slot_cxl20_capable(&self) -> bool {
1073        self.raw & 0x40 == 0x40
1074    }
1075
1076    /// Flexbus slot, CXL 3.0 capable
1077    pub fn flexbus_slot_cxl30_capable(&self) -> bool {
1078        self.raw & 0x80 == 0x80
1079    }
1080}
1081
1082impl fmt::Debug for SystemSlotCharacteristics2 {
1083    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1084        fmt.debug_struct(std::any::type_name::<SystemSlotCharacteristics2>())
1085            .field("raw", &self.raw)
1086            .field(
1087                "supports_power_management_event",
1088                &self.supports_power_management_event(),
1089            )
1090            .field(
1091                "supports_hot_plug_devices",
1092                &self.supports_hot_plug_devices(),
1093            )
1094            .field("supports_smbus_signal", &self.supports_smbus_signal())
1095            .field("supports_bifurcation", &self.supports_bifurcation())
1096            .field("supports_suprise_removal", &self.supports_suprise_removal())
1097            .field(
1098                "flexbus_slot_cxl10_capable",
1099                &self.flexbus_slot_cxl10_capable(),
1100            )
1101            .field(
1102                "flexbus_slot_cxl20_capable",
1103                &self.flexbus_slot_cxl20_capable(),
1104            )
1105            .field(
1106                "flexbus_slot_cxl30_capable",
1107                &self.flexbus_slot_cxl30_capable(),
1108            )
1109            .finish()
1110    }
1111}
1112
1113impl Serialize for SystemSlotCharacteristics2 {
1114    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1115    where
1116        S: Serializer,
1117    {
1118        let mut state = serializer.serialize_struct("SystemSlotCharacteristics2", 8)?;
1119        state.serialize_field("raw", &self.raw)?;
1120        state.serialize_field(
1121            "supports_power_management_event",
1122            &self.supports_power_management_event(),
1123        )?;
1124        state.serialize_field(
1125            "supports_hot_plug_devices",
1126            &self.supports_hot_plug_devices(),
1127        )?;
1128        state.serialize_field("supports_smbus_signal", &self.supports_smbus_signal())?;
1129        state.serialize_field("supports_bifurcation", &self.supports_bifurcation())?;
1130        state.serialize_field("supports_suprise_removal", &self.supports_suprise_removal())?;
1131        state.serialize_field(
1132            "flexbus_slot_cxl10_capable",
1133            &self.flexbus_slot_cxl10_capable(),
1134        )?;
1135        state.serialize_field(
1136            "flexbus_slot_cxl20_capable",
1137            &self.flexbus_slot_cxl20_capable(),
1138        )?;
1139        state.serialize_field(
1140            "flexbus_slot_cxl30_capable",
1141            &self.flexbus_slot_cxl30_capable(),
1142        )?;
1143        state.end()
1144    }
1145}
1146
1147/// # Segment Group Number
1148#[derive(Serialize, Debug, PartialEq, Eq)]
1149pub enum SegmentGroupNumber {
1150    /// Single-Segment Topology (no group number)
1151    SingleSegment,
1152    /// Segment Group Number
1153    Number(u16),
1154    /// For devices that are not of types PCI, AGP, PCI-X, or PCI-Express
1155    /// and that do not have bus/device/function information.
1156    NotApplicable,
1157}
1158
1159impl From<u16> for SegmentGroupNumber {
1160    fn from(raw: u16) -> Self {
1161        match raw {
1162            0x00 => SegmentGroupNumber::SingleSegment,
1163            0xFF => SegmentGroupNumber::NotApplicable,
1164            _ => SegmentGroupNumber::Number(raw),
1165        }
1166    }
1167}
1168
1169/// # Bus Number
1170#[derive(Serialize, Debug, PartialEq, Eq)]
1171pub enum BusNumber {
1172    /// Bus Number
1173    Number(u8),
1174    /// For devices that are not of types PCI, AGP, PCI-X, or PCI-Express
1175    /// and that do not have bus/device/function information.
1176    NotApplicable,
1177}
1178
1179impl From<u8> for BusNumber {
1180    fn from(raw: u8) -> Self {
1181        match raw {
1182            0xFF => BusNumber::NotApplicable,
1183            _ => BusNumber::Number(raw),
1184        }
1185    }
1186}
1187
1188/// # Device/Function Number
1189#[derive(Serialize, Debug, PartialEq, Eq)]
1190pub enum DeviceFunctionNumber {
1191    /// Device/Function Number
1192    Number {
1193        ///Bits 7:3 – Device number
1194        device: u8,
1195        /// Bits 2:0 – Function number
1196        function: u8,
1197    },
1198    /// For devices that are not of types PCI, AGP, PCI-X, or PCI-Express
1199    /// and that do not have bus/device/function information.
1200    NotApplicable,
1201}
1202
1203impl From<u8> for DeviceFunctionNumber {
1204    fn from(raw: u8) -> Self {
1205        match raw {
1206            0xFF => DeviceFunctionNumber::NotApplicable,
1207            _ => DeviceFunctionNumber::Number {
1208                device: (raw & 0b11111000) >> 3,
1209                function: raw & 0b00000111,
1210            },
1211        }
1212    }
1213}
1214
1215/// # Slot Peer Group entry within [SMBiosSystemSlot]
1216pub struct SlotPeerGroup<'a> {
1217    system_slot: &'a SMBiosSystemSlot<'a>,
1218    entry_offset: usize,
1219}
1220
1221impl<'a> SlotPeerGroup<'a> {
1222    /// Size in bytes for this structure
1223    const SIZE: usize = 5;
1224    const SEGMENT_GROUP_NUMBER_OFFSET: usize = 0;
1225    const BUS_NUMBER_OFFSET: usize = 2;
1226    const DEVICE_FUNCTION_NUMBER_OFFSET: usize = 3;
1227    const DATA_BUS_WIDTH_OFFSET: usize = 4;
1228
1229    fn new(system_slot: &'a SMBiosSystemSlot<'a>, entry_offset: usize) -> Self {
1230        Self {
1231            system_slot,
1232            entry_offset,
1233        }
1234    }
1235
1236    /// Segment Group Number (Peer)
1237    pub fn segment_group_number(&self) -> Option<u16> {
1238        self.system_slot
1239            .parts()
1240            .get_field_word(self.entry_offset + Self::SEGMENT_GROUP_NUMBER_OFFSET)
1241    }
1242
1243    /// Bus Number (Peer)
1244    pub fn bus_number(&self) -> Option<u8> {
1245        self.system_slot
1246            .parts()
1247            .get_field_byte(self.entry_offset + Self::BUS_NUMBER_OFFSET)
1248    }
1249
1250    /// Device/Function Number (Peer)
1251    pub fn device_function_number(&self) -> Option<u8> {
1252        self.system_slot
1253            .parts()
1254            .get_field_byte(self.entry_offset + Self::DEVICE_FUNCTION_NUMBER_OFFSET)
1255    }
1256
1257    /// Data bus width (Peer)
1258    ///
1259    /// Indicates electrical bus width of peer Segment/Bus/Device/Function.
1260    pub fn data_bus_width(&self) -> Option<u8> {
1261        self.system_slot
1262            .parts()
1263            .get_field_byte(self.entry_offset + Self::DATA_BUS_WIDTH_OFFSET)
1264    }
1265}
1266
1267impl fmt::Debug for SlotPeerGroup<'_> {
1268    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1269        fmt.debug_struct(std::any::type_name::<SlotPeerGroup<'_>>())
1270            .field("segment_group_number", &self.segment_group_number())
1271            .field("bus_number", &self.bus_number())
1272            .field("device_function_number", &self.device_function_number())
1273            .field("data_bus_width", &self.data_bus_width())
1274            .finish()
1275    }
1276}
1277
1278impl Serialize for SlotPeerGroup<'_> {
1279    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1280    where
1281        S: Serializer,
1282    {
1283        let mut state = serializer.serialize_struct("SlotPeerGroup", 4)?;
1284        state.serialize_field("segment_group_number", &self.segment_group_number())?;
1285        state.serialize_field("bus_number", &self.bus_number())?;
1286        state.serialize_field("device_function_number", &self.device_function_number())?;
1287        state.serialize_field("data_bus_width", &self.data_bus_width())?;
1288        state.end()
1289    }
1290}
1291
1292/// # On-board Device Itereator for [SlotPeerGroup]s contained within [SMBiosSystemSlot]
1293pub struct SlotPeerGroupIterator<'a> {
1294    data: &'a SMBiosSystemSlot<'a>,
1295    current_index: usize,
1296    current_entry: usize,
1297    number_of_entries: usize,
1298}
1299
1300impl<'a> SlotPeerGroupIterator<'a> {
1301    const PEER_GROUPS_OFFSET: usize = 0x13;
1302
1303    fn new(data: &'a SMBiosSystemSlot<'a>) -> Self {
1304        SlotPeerGroupIterator {
1305            data: data,
1306            current_index: Self::PEER_GROUPS_OFFSET,
1307            current_entry: 0,
1308            number_of_entries: data.peer_group_count().unwrap_or(0),
1309        }
1310    }
1311
1312    fn reset(&mut self) {
1313        self.current_index = Self::PEER_GROUPS_OFFSET;
1314        self.current_entry = 0;
1315    }
1316}
1317
1318impl<'a> IntoIterator for &'a SlotPeerGroupIterator<'a> {
1319    type Item = SlotPeerGroup<'a>;
1320    type IntoIter = SlotPeerGroupIterator<'a>;
1321
1322    fn into_iter(self) -> Self::IntoIter {
1323        SlotPeerGroupIterator {
1324            data: self.data,
1325            current_index: SlotPeerGroupIterator::PEER_GROUPS_OFFSET,
1326            current_entry: 0,
1327            number_of_entries: self.data.peer_group_count().unwrap_or(0),
1328        }
1329    }
1330}
1331
1332impl<'a> Iterator for SlotPeerGroupIterator<'a> {
1333    type Item = SlotPeerGroup<'a>;
1334
1335    fn next(&mut self) -> Option<Self::Item> {
1336        if self.current_entry == self.number_of_entries {
1337            self.reset();
1338            return None;
1339        }
1340
1341        let next_index = self.current_index + SlotPeerGroup::SIZE;
1342        match self
1343            .data
1344            .parts()
1345            .get_field_data(self.current_index, next_index)
1346        {
1347            Some(_) => {
1348                let result = SlotPeerGroup::new(self.data, self.current_index);
1349                self.current_index = next_index;
1350                self.current_entry += 1;
1351                Some(result)
1352            }
1353            None => {
1354                self.reset();
1355                None
1356            }
1357        }
1358    }
1359}
1360
1361impl<'a> fmt::Debug for SlotPeerGroupIterator<'a> {
1362    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1363        fmt.debug_list().entries(self.into_iter()).finish()
1364    }
1365}
1366
1367impl<'a> Serialize for SlotPeerGroupIterator<'a> {
1368    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1369    where
1370        S: Serializer,
1371    {
1372        let groups: Vec<SlotPeerGroup<'_>> = self.into_iter().collect();
1373        let mut seq = serializer.serialize_seq(Some(groups.len()))?;
1374        for e in groups {
1375            seq.serialize_element(&e)?;
1376        }
1377        seq.end()
1378    }
1379}
1380
1381#[cfg(test)]
1382mod tests {
1383    use super::*;
1384
1385    #[test]
1386    fn unit_test() {
1387        // System Slot structure lengths and their versions:
1388        // 0Ch for version 2.0 implementations
1389        // 0Dh for versions 2.1 to 2.5
1390        // 11h for versions 2.6 to 3.1.1
1391        // Minimum of 11h for version 3.2 and later.
1392
1393        // 2.6 to 3.1.1 System Slot structure (0x11 length, it does not include _data_bus_width()_ and beyond)
1394        let struct_type9 = vec![
1395            0x09, 0x11, 0x1C, 0x00, 0x01, 0xA5, 0x0D, 0x04, 0x04, 0x05, 0x07, 0x0C, 0x01, 0x00,
1396            0x00, 0x00, 0x08, 0x4A, 0x36, 0x42, 0x32, 0x00, 0x00,
1397        ];
1398
1399        let parts = UndefinedStruct::new(&struct_type9);
1400        let test_struct = SMBiosSystemSlot::new(&parts);
1401
1402        assert_eq!(
1403            test_struct.slot_designation().to_string(),
1404            "J6B2".to_string()
1405        );
1406
1407        assert_eq!(
1408            *test_struct.system_slot_type().unwrap(),
1409            SystemSlotType::PciExpress(
1410                PciExpressGeneration::PCIExpressGen1,
1411                PciExpressSlotWidth::UndefinedSlotWidth,
1412            )
1413        );
1414
1415        assert_eq!(*test_struct.slot_data_bus_width().unwrap(), SlotWidth::X16);
1416
1417        let slot_id = test_struct.slot_id().unwrap();
1418        assert_eq!(slot_id.byte_0(), 5);
1419        assert_eq!(slot_id.byte_1(), 7);
1420
1421        // 2.6 to 3.1.1 has no data_bus_width() field or beyond fields
1422        assert!(test_struct.data_bus_width().is_none());
1423
1424        // 3.4 System Slot structure
1425        let struct_type9 = vec![
1426            0x09, 0x1C, 0x1C, 0x00, 0x01, 0xA5, 0x0D, 0x04, 0x04, 0x00, 0x00, 0x0C, 0x01, 0x00,
1427            0x00, 0x00, 0x08, 0x99, 0x01, 0x23, 0x01, 0x04, 0x05, 0x06, 0x07, 0x08, 0xAB, 0x09,
1428            0x4A, 0x36, 0x42, 0x32, 0x00, 0x00,
1429        ];
1430        let parts = UndefinedStruct::new(&struct_type9);
1431        let test_struct = SMBiosSystemSlot::new(&parts);
1432
1433        // 3.2 fields
1434        assert_eq!(test_struct.data_bus_width(), Some(0x99));
1435        assert_eq!(test_struct.peer_group_count(), Some(0x01));
1436
1437        let mut iterator = test_struct.peer_group_iterator().into_iter();
1438        let first = iterator.next().unwrap();
1439        assert_eq!(first.segment_group_number(), Some(0x0123));
1440        assert_eq!(first.bus_number(), Some(0x04));
1441        assert_eq!(first.device_function_number(), Some(0x05));
1442        assert_eq!(first.data_bus_width(), Some(0x06));
1443
1444        // 3.4 fields
1445        // TODO:
1446        // Note: There will be an erratum published for these fields.  For this test case
1447        // the field offsets have been shifted back by 1 from 0x14, 0x15, 0x16 (+ 5 * n), to 0x13...
1448        assert_eq!(test_struct.slot_information(), Some(0x07));
1449        assert_eq!(*test_struct.slot_physical_width().unwrap(), SlotWidth::X1);
1450        assert_eq!(test_struct.slot_pitch(), Some(0x09AB));
1451
1452        println!("{:?}", test_struct);
1453    }
1454}