Skip to main content

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