smbioslib/structs/types/
system_event_log.rs

1use crate::{SMBiosStruct, UndefinedStruct};
2use serde::{ser::SerializeSeq, ser::SerializeStruct, Serialize, Serializer};
3use std::fmt;
4use std::ops::Deref;
5
6/// # System Event Log (Type 15)
7///
8/// The presence of this structure within the SMBIOS data returned for a system indicates that the system
9/// supports an event log. An event log is a fixed-length area within a non-volatile
10/// storage element, starting with a fixed-length (and vendor-specific) header record, followed by one or more
11/// variable-length log records.
12///
13/// Compliant with:
14/// DMTF SMBIOS Reference Specification 3.4.0 (DSP0134)
15/// Document Date: 2020-07-17
16pub struct SMBiosSystemEventLog<'a> {
17    parts: &'a UndefinedStruct,
18}
19
20impl<'a> SMBiosStruct<'a> for SMBiosSystemEventLog<'a> {
21    const STRUCT_TYPE: u8 = 15u8;
22
23    fn new(parts: &'a UndefinedStruct) -> Self {
24        Self { parts }
25    }
26
27    fn parts(&self) -> &'a UndefinedStruct {
28        self.parts
29    }
30}
31
32impl<'a> SMBiosSystemEventLog<'a> {
33    const LOG_TYPE_DESCRIPTORS_OFFSET: usize = 0x17usize;
34
35    /// Length, in bytes, of the overall event log area,
36    /// from the first byte of header to the last byte of data
37    pub fn log_area_length(&self) -> Option<u16> {
38        self.parts.get_field_word(0x04)
39    }
40
41    /// Defines the starting offset (or index) within the
42    /// nonvolatile storage of the event-log’s header,
43    /// from the Access Method Address
44    /// For single-byte indexed I/O accesses, the
45    /// most-significant byte of the start offset is set
46    /// to 00h.
47    pub fn log_header_start_offset(&self) -> Option<u16> {
48        self.parts.get_field_word(0x06)
49    }
50
51    /// Defines the starting offset (or index) within the
52    /// nonvolatile storage of the event-log’s first
53    /// data byte, from the Access Method Address
54    /// For single-byte indexed I/O accesses, the
55    /// most-significant byte of the start offset is set
56    /// to 00h.
57    ///
58    /// NOTE: The data directly follows any header
59    /// information. Therefore, the header length
60    /// can be determined by subtracting the
61    /// Header Start Offset from the Data Start
62    /// Offset.
63    pub fn log_data_start_offset(&self) -> Option<u16> {
64        self.parts.get_field_word(0x08)
65    }
66
67    /// Defines the Location and Method used by higher-level software to access the log area
68    pub fn access_method(&self) -> Option<AccessMethodData> {
69        self.parts
70            .get_field_byte(0x0A)
71            .map(|raw| AccessMethodData::from(raw))
72    }
73
74    /// Current status of the system event-log
75    pub fn log_status(&self) -> Option<LogStatus> {
76        self.parts
77            .get_field_byte(0x0B)
78            .map(|raw| LogStatus::from(raw))
79    }
80
81    /// Unique token that is reassigned every time
82    /// the event log changes
83    ///
84    /// Can be used to determine if additional events
85    /// have occurred since the last time the log was
86    /// read.
87    pub fn log_change_token(&self) -> Option<u32> {
88        self.parts.get_field_dword(0x0C)
89    }
90
91    /// Address associated with the access method
92    ///
93    /// The data present depends on the Access
94    /// Method field value
95    pub fn access_method_address(&self) -> Option<u32> {
96        self.parts.get_field_dword(0x10)
97    }
98
99    /// Format of the log header area
100    pub fn log_header_format(&self) -> Option<HeaderFormatData> {
101        self.parts
102            .get_field_byte(0x14)
103            .map(|raw| HeaderFormatData::from(raw))
104    }
105
106    /// Number of supported event log type
107    /// descriptors that follow
108    ///
109    /// If the value is 0, the list that starts at offset
110    /// 17h is not present.
111    pub fn number_of_supported_log_type_descriptors(&self) -> Option<u8> {
112        self.parts.get_field_byte(0x15)
113    }
114
115    /// Number of bytes associated with each type
116    /// entry in the list below
117    /// The value is currently “hard-coded” as 2,
118    /// because each entry consists of two bytes.
119    /// This field’s presence allows future additions
120    /// to the type list. Software that interprets the
121    /// following list should not assume a list entry’s
122    /// length.
123    pub fn length_of_each_log_type_descriptor(&self) -> Option<u8> {
124        self.parts.get_field_byte(0x16)
125    }
126
127    /// Type Descriptors
128    pub fn type_descriptors(&self) -> Option<TypeDescriptors<'_>> {
129        TypeDescriptors::new(self)
130    }
131}
132
133impl fmt::Debug for SMBiosSystemEventLog<'_> {
134    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
135        fmt.debug_struct(std::any::type_name::<SMBiosSystemEventLog<'_>>())
136            .field("header", &self.parts.header)
137            .field("log_area_length", &self.log_area_length())
138            .field("log_header_start_offset", &self.log_header_start_offset())
139            .field("log_data_start_offset", &self.log_data_start_offset())
140            .field("access_method", &self.access_method())
141            .field("log_status", &self.log_status())
142            .field("log_change_token", &self.log_change_token())
143            .field("access_method_address", &self.access_method_address())
144            .field("log_header_format", &self.log_header_format())
145            .field(
146                "number_of_supported_log_type_descriptors",
147                &self.number_of_supported_log_type_descriptors(),
148            )
149            .field(
150                "length_of_each_log_type_descriptor",
151                &self.length_of_each_log_type_descriptor(),
152            )
153            .field("type_descriptors", &self.type_descriptors())
154            .finish()
155    }
156}
157
158impl Serialize for SMBiosSystemEventLog<'_> {
159    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
160    where
161        S: Serializer,
162    {
163        let mut state = serializer.serialize_struct("SMBiosSystemEventLog", 12)?;
164        state.serialize_field("header", &self.parts.header)?;
165        state.serialize_field("log_area_length", &self.log_area_length())?;
166        state.serialize_field("log_header_start_offset", &self.log_header_start_offset())?;
167        state.serialize_field("log_data_start_offset", &self.log_data_start_offset())?;
168        state.serialize_field("access_method", &self.access_method())?;
169        state.serialize_field("log_status", &self.log_status())?;
170        state.serialize_field("log_change_token", &self.log_change_token())?;
171        state.serialize_field("access_method_address", &self.access_method_address())?;
172        state.serialize_field("log_header_format", &self.log_header_format())?;
173        state.serialize_field(
174            "number_of_supported_log_type_descriptors",
175            &self.number_of_supported_log_type_descriptors(),
176        )?;
177        state.serialize_field(
178            "length_of_each_log_type_descriptor",
179            &self.length_of_each_log_type_descriptor(),
180        )?;
181        state.serialize_field("type_descriptors", &self.type_descriptors())?;
182        state.end()
183    }
184}
185
186/// # System Event Log - Log Type Data
187pub struct LogTypeData {
188    /// Raw value
189    ///
190    /// _raw_ is most useful when _value_ is None.
191    /// This is most likely to occur when the standard was updated but
192    /// this library code has not been updated to match the current
193    /// standard.
194    pub raw: u8,
195    /// The contained [LogType] value
196    pub value: LogType,
197}
198
199impl fmt::Debug for LogTypeData {
200    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
201        fmt.debug_struct(std::any::type_name::<LogTypeData>())
202            .field("raw", &self.raw)
203            .field("value", &self.value)
204            .finish()
205    }
206}
207
208impl Serialize for LogTypeData {
209    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
210    where
211        S: Serializer,
212    {
213        let mut state = serializer.serialize_struct("LogTypeData", 2)?;
214        state.serialize_field("raw", &self.raw)?;
215        state.serialize_field("value", &self.value)?;
216        state.end()
217    }
218}
219
220impl fmt::Display for LogTypeData {
221    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222        match &self.value {
223            LogType::None => write!(f, "{}", &self.raw),
224            _ => write!(f, "{:?}", &self.value),
225        }
226    }
227}
228
229impl Deref for LogTypeData {
230    type Target = LogType;
231
232    fn deref(&self) -> &Self::Target {
233        &self.value
234    }
235}
236
237/// # System Event Log - Log Type
238#[derive(Serialize, Debug, PartialEq, Eq)]
239pub enum LogType {
240    /// Single-bit ECC memory error
241    SingleBitEccMemoryError,
242    /// Multi-bit ECC memory error
243    MultiBitEccMemoryError,
244    /// Parity memory error
245    ParityMemoryError,
246    /// Bus time-out
247    BusTimeOut,
248    /// I/O Channel Check
249    IOChannelCheck,
250    /// Software NMI
251    SoftwareNmi,
252    /// POST Memory Resize
253    PostMemoryResize,
254    /// POST Error
255    PostError,
256    /// PCI Parity Error
257    PciParityError,
258    /// PCI System Error
259    PciSystemError,
260    /// CPU Failure
261    CpuFailure,
262    /// EISA FailSafe Timer time-out
263    EisaFailSafeTimerTimeout,
264    /// Correctable memory log disabled
265    CorrectableMemoryLogDisabled,
266    /// Logging disabled for a specific Event Type — too many errors of the same type received in a short amount of time
267    LoggingDisabledForSpecificEventType,
268    /// Reserved
269    Reserved0F,
270    /// System Limit Exceeded (for example, voltage or temperature threshold exceeded)
271    SystemLimitExceeded,
272    /// Asynchronous hardware timer expired and issued a system reset
273    AsyncHardwareTimerExpired,
274    /// System configuration information
275    SystemConfigurationInformation,
276    /// Hard-disk information
277    HardDiskInformation,
278    /// System reconfigured
279    SystemReconfigured,
280    /// Uncorrectable CPU-complex error
281    UncorrectableCpuComplexError,
282    /// Log Area Reset/Cleared
283    LogAreaReset,
284    /// System boot. If implemented, this log entry is guaranteed to be the first one written on any system boot.
285    SystemBoot,
286    /// A value unknown to this standard, check the raw value
287    None,
288}
289
290impl From<u8> for LogTypeData {
291    fn from(raw: u8) -> Self {
292        LogTypeData {
293            value: match raw {
294                0x01 => LogType::SingleBitEccMemoryError,
295                0x02 => LogType::MultiBitEccMemoryError,
296                0x03 => LogType::ParityMemoryError,
297                0x04 => LogType::BusTimeOut,
298                0x05 => LogType::IOChannelCheck,
299                0x06 => LogType::SoftwareNmi,
300                0x07 => LogType::PostMemoryResize,
301                0x08 => LogType::PostError,
302                0x09 => LogType::PciParityError,
303                0x0A => LogType::PciSystemError,
304                0x0B => LogType::CpuFailure,
305                0x0C => LogType::EisaFailSafeTimerTimeout,
306                0x0D => LogType::CorrectableMemoryLogDisabled,
307                0x0E => LogType::LoggingDisabledForSpecificEventType,
308                0x0F => LogType::Reserved0F,
309                0x10 => LogType::SystemLimitExceeded,
310                0x11 => LogType::AsyncHardwareTimerExpired,
311                0x12 => LogType::SystemConfigurationInformation,
312                0x13 => LogType::HardDiskInformation,
313                0x14 => LogType::SystemReconfigured,
314                0x15 => LogType::UncorrectableCpuComplexError,
315                0x16 => LogType::LogAreaReset,
316                0x17 => LogType::SystemBoot,
317                _ => LogType::None,
318            },
319            raw,
320        }
321    }
322}
323
324/// # System Event Log - Variable Data Format Type Data
325pub struct VariableDataFormatTypeData {
326    /// Raw value
327    ///
328    /// _raw_ is most useful when _value_ is None.
329    /// This is most likely to occur when the standard was updated but
330    /// this library code has not been updated to match the current
331    /// standard.
332    pub raw: u8,
333    /// The contained [VariableDataFormatType] value
334    pub value: VariableDataFormatType,
335}
336
337impl fmt::Debug for VariableDataFormatTypeData {
338    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
339        fmt.debug_struct(std::any::type_name::<VariableDataFormatTypeData>())
340            .field("raw", &self.raw)
341            .field("value", &self.value)
342            .finish()
343    }
344}
345
346impl Serialize for VariableDataFormatTypeData {
347    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
348    where
349        S: Serializer,
350    {
351        let mut state = serializer.serialize_struct("VariableDataFormatTypeData", 2)?;
352        state.serialize_field("raw", &self.raw)?;
353        state.serialize_field("value", &self.value)?;
354        state.end()
355    }
356}
357
358impl fmt::Display for VariableDataFormatTypeData {
359    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360        match &self.value {
361            VariableDataFormatType::None => write!(f, "{}", &self.raw),
362            _ => write!(f, "{:?}", &self.value),
363        }
364    }
365}
366
367impl Deref for VariableDataFormatTypeData {
368    type Target = VariableDataFormatType;
369
370    fn deref(&self) -> &Self::Target {
371        &self.value
372    }
373}
374
375/// # System Event Log - Variable Data Format Type
376#[derive(Serialize, Debug, PartialEq, Eq)]
377pub enum VariableDataFormatType {
378    /// No standard format data is available; the first byte of the variable data (if present) contains OEM-specific unformatted information.
379    NoStandardFormat,
380    /// The first WORD of the variable data contains the handle of the SMBIOS structure associated with the hardware element that failed.
381    Handle,
382    /// The first DWORD of the variable data contains a multiple-event counter (see 7.16.6.3 for details).
383    MultipleEvent,
384    /// The first WORD of the variable data contains the handle of the SMBIOS structure associated with the hardware element that failed; it is followed by a DWORD containing a multiple-event counter (see 7.16.6.3 for details).
385    MultipleEventHandle,
386    /// The first two DWORDs of the variable data contain the POST Results Bitmap, as described in 7.16.6.4.
387    PostResultsBitmap,
388    /// The first DWORD of the variable data contains a value that identifies a system-management condition. See 7.16.6.5 for the enumerated values.
389    SystemManagementType,
390    /// The first DWORD of the variable data contains a value that identifies a system-management condition. (See 7.16.6.5 for the enumerated values.) This DWORD is directly followed by a DWORD that contains a multiple- event counter (see 7.16.6.3 for details).
391    MultipleEventSystemManagementType,
392    /// A value unknown to this standard, check the raw value
393    None,
394}
395
396impl From<u8> for VariableDataFormatTypeData {
397    fn from(raw: u8) -> Self {
398        VariableDataFormatTypeData {
399            value: match raw {
400                0x00 => VariableDataFormatType::NoStandardFormat,
401                0x01 => VariableDataFormatType::Handle,
402                0x02 => VariableDataFormatType::MultipleEvent,
403                0x03 => VariableDataFormatType::MultipleEventHandle,
404                0x04 => VariableDataFormatType::PostResultsBitmap,
405                0x05 => VariableDataFormatType::SystemManagementType,
406                0x06 => VariableDataFormatType::MultipleEventSystemManagementType,
407                _ => VariableDataFormatType::None,
408            },
409            raw,
410        }
411    }
412}
413
414/// # System Event Log - Access Method Data
415pub struct AccessMethodData {
416    /// Raw value
417    ///
418    /// _raw_ is most useful when _value_ is None.
419    /// This is most likely to occur when the standard was updated but
420    /// this library code has not been updated to match the current
421    /// standard.
422    pub raw: u8,
423    /// The contained [AccessMethod] value
424    pub value: AccessMethod,
425}
426
427impl fmt::Debug for AccessMethodData {
428    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
429        fmt.debug_struct(std::any::type_name::<AccessMethodData>())
430            .field("raw", &self.raw)
431            .field("value", &self.value)
432            .finish()
433    }
434}
435
436impl Serialize for AccessMethodData {
437    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
438    where
439        S: Serializer,
440    {
441        let mut state = serializer.serialize_struct("AccessMethodData", 2)?;
442        state.serialize_field("raw", &self.raw)?;
443        state.serialize_field("value", &self.value)?;
444        state.end()
445    }
446}
447
448impl Deref for AccessMethodData {
449    type Target = AccessMethod;
450
451    fn deref(&self) -> &Self::Target {
452        &self.value
453    }
454}
455
456impl From<u8> for AccessMethodData {
457    fn from(raw: u8) -> Self {
458        AccessMethodData {
459            value: AccessMethod::from(raw),
460            raw,
461        }
462    }
463}
464/// # System Event Log - Access Method
465///
466/// Defines the Location and Method used by higher-level software to access the log area.
467#[derive(Serialize, Debug, PartialEq, Eq)]
468pub enum AccessMethod {
469    /// 00h Indexed I/O
470    ///
471    /// 1 8-bit index port, 1 8-bit data port. The Access Method Address field contains the
472    /// 16-bit I/O addresses for the index and data ports. See 7.16.2.1 for usage details.
473    IndexedIO18Bit,
474    /// 01h Indexed I/O
475    ///
476    /// 2 8-bit index ports, 1 8-bit data port. The Access Method Address field contains the
477    /// 16-bit I/O address for the index and data ports. See 7.16.2.2 for usage details.
478    IndexedIO28Bit,
479    /// 02h Indexed I/O
480    ///
481    /// 1 16-bit index port, 1 8-bit data port. The Access Method Address field contains the
482    /// 16-bit I/O address for the index and data ports. See 7.16.2.3 for usage details.
483    IndexedIO116Bit,
484    /// 03h Memory-mapped physical 32-bit address.
485    ///
486    /// The Access Method Address field contains the 4-byte (Intel DWORD format) starting physical address.
487    MemoryMapped32Bit,
488    /// 04h Available through General-Purpose NonVolatile Data functions.
489    ///
490    /// The Access Method Address field contains the 2-byte (Intel WORD format) GPNV handle.
491    GeneralPurposeNonVolatile,
492    /// A value unknown to this standard, check the raw value
493    None,
494}
495
496impl From<u8> for AccessMethod {
497    fn from(raw: u8) -> Self {
498        match raw {
499            0x00 => AccessMethod::IndexedIO18Bit,
500            0x01 => AccessMethod::IndexedIO28Bit,
501            0x02 => AccessMethod::IndexedIO116Bit,
502            0x03 => AccessMethod::MemoryMapped32Bit,
503            0x04 => AccessMethod::GeneralPurposeNonVolatile,
504            _ => AccessMethod::None,
505        }
506    }
507}
508
509/// System Event Log Type Descriptor
510///
511/// Each entry consists of a 1-byte type field and a 1-byte data-format descriptor, as shown in Table 61. The
512/// presence of an entry identifies that the Log Type is supported by the system and the format of any
513/// variable data that accompanies the first bytes of the log’s variable data — a specific log record might
514/// have more variable data than specified by its Variable Data Format Type.
515pub struct EventLogTypeDescriptor<'a> {
516    /// Raw byte slice for this event log type descriptor
517    pub raw: &'a [u8],
518}
519
520impl<'a> EventLogTypeDescriptor<'a> {
521    const MINIMUM_RAW_SIZE: usize = 2usize;
522    const LOG_TYPE_OFFSET: usize = 0usize;
523    const VARIABLE_DATA_FORMAT_TYPE_OFFSET: usize = 1usize;
524
525    fn new(raw: &'a [u8]) -> Option<Self> {
526        if raw.len() < Self::MINIMUM_RAW_SIZE {
527            None
528        } else {
529            Some(Self { raw })
530        }
531    }
532
533    /// Event Log Type
534    pub fn log_type(&self) -> LogTypeData {
535        LogTypeData::from(self.raw[Self::LOG_TYPE_OFFSET])
536    }
537
538    /// Event Log Variable Data Format Type
539    ///
540    /// The Variable Data Format Type, specified in the Event Log structure’s Supported Event Type fields,
541    /// identifies the standard format that application software can apply to the first n bytes of the associated.
542    /// Log Type’s variable data.Additional OEM-specific data might follow in the log’s variable data field.
543    pub fn variable_data_format_type(&self) -> VariableDataFormatTypeData {
544        VariableDataFormatTypeData::from(self.raw[Self::VARIABLE_DATA_FORMAT_TYPE_OFFSET])
545    }
546}
547
548impl<'a> fmt::Debug for EventLogTypeDescriptor<'a> {
549    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
550        fmt.debug_struct(std::any::type_name::<EventLogTypeDescriptor<'_>>())
551            .field("raw", &self.raw)
552            .field("log_type", &self.log_type())
553            .field(
554                "variable_data_format_type",
555                &self.variable_data_format_type(),
556            )
557            .finish()
558    }
559}
560
561impl<'a> Serialize for EventLogTypeDescriptor<'a> {
562    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
563    where
564        S: Serializer,
565    {
566        let mut state = serializer.serialize_struct("EventLogTypeDescriptor", 3)?;
567        state.serialize_field("raw", &self.raw)?;
568        state.serialize_field("log_type", &self.log_type())?;
569        state.serialize_field(
570            "variable_data_format_type",
571            &self.variable_data_format_type(),
572        )?;
573        state.end()
574    }
575}
576
577/// # System Event Log Type Descriptors within [SMBiosSystemEventLog]
578pub struct TypeDescriptors<'a> {
579    raw: &'a [u8],
580    record_count: usize,
581    record_length: usize,
582}
583
584impl<'a> TypeDescriptors<'a> {
585    fn new(system_event_log: &'a SMBiosSystemEventLog<'a>) -> Option<Self> {
586        system_event_log
587            .length_of_each_log_type_descriptor()
588            .and_then(|record_length| {
589                system_event_log
590                    .number_of_supported_log_type_descriptors()
591                    .and_then(|record_count| {
592                        system_event_log
593                            .parts()
594                            .get_field_data(
595                                SMBiosSystemEventLog::LOG_TYPE_DESCRIPTORS_OFFSET,
596                                SMBiosSystemEventLog::LOG_TYPE_DESCRIPTORS_OFFSET
597                                    + (record_length as usize * record_count as usize),
598                            )
599                            .and_then(|raw| {
600                                Some(Self {
601                                    raw,
602                                    record_count: record_count as usize,
603                                    record_length: record_length as usize,
604                                })
605                            })
606                    })
607            })
608    }
609}
610
611impl<'a> fmt::Debug for TypeDescriptors<'a> {
612    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
613        fmt.debug_struct(std::any::type_name::<TypeDescriptors<'_>>())
614            .field("descriptors", &self.into_iter())
615            .finish()
616    }
617}
618
619impl<'a> Serialize for TypeDescriptors<'a> {
620    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
621    where
622        S: Serializer,
623    {
624        let mut seq = serializer.serialize_seq(Some(self.record_count))?;
625        for e in self {
626            seq.serialize_element(&e)?;
627        }
628        seq.end()
629    }
630}
631
632/// # Iterates over the [EventLogTypeDescriptor] entries within [TypeDescriptors]
633pub struct TypeDescriptorsIterator<'a> {
634    descriptors: &'a TypeDescriptors<'a>,
635    current_index: usize,
636    current_entry: usize,
637}
638
639impl<'a> TypeDescriptorsIterator<'a> {
640    fn reset(&mut self) {
641        self.current_index = 0;
642        self.current_entry = 0;
643    }
644}
645
646impl<'a> IntoIterator for &'a TypeDescriptors<'a> {
647    type Item = EventLogTypeDescriptor<'a>;
648    type IntoIter = TypeDescriptorsIterator<'a>;
649
650    fn into_iter(self) -> Self::IntoIter {
651        TypeDescriptorsIterator {
652            descriptors: self,
653            current_index: 0,
654            current_entry: 0,
655        }
656    }
657}
658
659impl<'a> Iterator for TypeDescriptorsIterator<'a> {
660    type Item = EventLogTypeDescriptor<'a>;
661
662    fn next(&mut self) -> Option<Self::Item> {
663        if self.current_entry == self.descriptors.record_count {
664            self.reset();
665            return None;
666        }
667
668        let next_index = self.current_index + self.descriptors.record_length;
669        match EventLogTypeDescriptor::new(&self.descriptors.raw[self.current_index..next_index]) {
670            Some(event_log_type_descriptor) => {
671                self.current_index = next_index;
672                self.current_entry += 1;
673                Some(event_log_type_descriptor)
674            }
675            None => {
676                self.reset();
677                None
678            }
679        }
680    }
681}
682
683impl<'a> fmt::Debug for TypeDescriptorsIterator<'a> {
684    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
685        fmt.debug_list()
686            .entries(self.descriptors.into_iter())
687            .finish()
688    }
689}
690
691impl<'a> Serialize for TypeDescriptorsIterator<'a> {
692    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
693    where
694        S: Serializer,
695    {
696        let descriptors: Vec<EventLogTypeDescriptor<'_>> = self.descriptors.into_iter().collect();
697        let mut seq = serializer.serialize_seq(Some(descriptors.len()))?;
698        for e in descriptors {
699            seq.serialize_element(&e)?;
700        }
701        seq.end()
702    }
703}
704
705/// # System Event Log - Log Status
706#[derive(PartialEq, Eq)]
707pub struct LogStatus {
708    /// Raw value
709    pub raw: u8,
710}
711
712impl Deref for LogStatus {
713    type Target = u8;
714
715    fn deref(&self) -> &Self::Target {
716        &self.raw
717    }
718}
719
720impl From<u8> for LogStatus {
721    fn from(raw: u8) -> Self {
722        LogStatus { raw }
723    }
724}
725
726impl LogStatus {
727    /// If true, log area valid; otherwise false
728    pub fn log_area_valid(&self) -> bool {
729        self.raw & 0x01 == 0x01
730    }
731
732    /// If true log area full; otherwise false
733    pub fn log_area_full(&self) -> bool {
734        self.raw & 0x02 == 0x02
735    }
736}
737
738impl fmt::Debug for LogStatus {
739    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
740        fmt.debug_struct(std::any::type_name::<LogStatus>())
741            .field("raw", &self.raw)
742            .field("log_area_valid", &self.log_area_valid())
743            .field("log_area_full", &self.log_area_full())
744            .finish()
745    }
746}
747
748impl Serialize for LogStatus {
749    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
750    where
751        S: Serializer,
752    {
753        let mut state = serializer.serialize_struct("LogStatus", 3)?;
754        state.serialize_field("raw", &self.raw)?;
755        state.serialize_field("log_area_valid", &self.log_area_valid())?;
756        state.serialize_field("log_area_full", &self.log_area_full())?;
757        state.end()
758    }
759}
760
761/// # System Event Log - Header Format Data
762pub struct HeaderFormatData {
763    /// Raw value
764    ///
765    /// _raw_ is most useful when _value_ is None.
766    /// This is most likely to occur when the standard was updated but
767    /// this library code has not been updated to match the current
768    /// standard.
769    pub raw: u8,
770    /// The contained [HeaderFormat] value
771    pub value: HeaderFormat,
772}
773
774impl fmt::Debug for HeaderFormatData {
775    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
776        fmt.debug_struct(std::any::type_name::<HeaderFormatData>())
777            .field("raw", &self.raw)
778            .field("value", &self.value)
779            .finish()
780    }
781}
782
783impl Serialize for HeaderFormatData {
784    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
785    where
786        S: Serializer,
787    {
788        let mut state = serializer.serialize_struct("HeaderFormatData", 2)?;
789        state.serialize_field("raw", &self.raw)?;
790        state.serialize_field("value", &self.value)?;
791        state.end()
792    }
793}
794
795impl Deref for HeaderFormatData {
796    type Target = HeaderFormat;
797
798    fn deref(&self) -> &Self::Target {
799        &self.value
800    }
801}
802
803/// # System Event Log - Header Format
804#[derive(Serialize, Debug, PartialEq, Eq)]
805pub enum HeaderFormat {
806    /// No header (for example, the header is 0 bytes in length)
807    NoHeader,
808    /// Type 1 log header
809    Type1LogHeader,
810    /// A value unknown to this standard, check the raw value
811    None,
812}
813
814impl From<u8> for HeaderFormatData {
815    fn from(raw: u8) -> Self {
816        HeaderFormatData {
817            value: match raw {
818                0x00 => HeaderFormat::NoHeader,
819                0x01 => HeaderFormat::Type1LogHeader,
820                _ => HeaderFormat::None,
821            },
822            raw,
823        }
824    }
825}
826
827#[cfg(test)]
828mod tests {
829    use super::*;
830
831    #[test]
832    fn unit_test() {
833        let struct_type15 = vec![
834            0x0F, 0x49, 0x3D, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x03, 0x01, 0x05, 0x00,
835            0x00, 0x00, 0x18, 0x20, 0xAE, 0x6A, 0x01, 0x19, 0x02, 0x01, 0x03, 0x02, 0x03, 0x03,
836            0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x04, 0x09, 0x03, 0x0A,
837            0x03, 0x0B, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12,
838            0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0xFF, 0x00, 0xE0,
839            0xE0, 0xE1, 0xE1, 0x00, 0x00,
840        ];
841
842        let parts = UndefinedStruct::new(&struct_type15);
843        let test_struct = SMBiosSystemEventLog::new(&parts);
844
845        println!("{:?}", test_struct);
846        assert_eq!(test_struct.log_area_length(), Some(4096));
847        assert_eq!(test_struct.log_header_start_offset(), Some(0));
848        assert_eq!(test_struct.log_data_start_offset(), Some(16));
849        assert_eq!(
850            *test_struct.access_method().unwrap(),
851            AccessMethod::MemoryMapped32Bit
852        );
853        assert_eq!(
854            test_struct.log_status().unwrap(),
855            LogStatus::from(0b0000_0001)
856        );
857        assert_eq!(test_struct.log_change_token(), Some(5));
858        assert_eq!(test_struct.access_method_address(), Some(1789796376));
859        assert_eq!(
860            *test_struct.log_header_format().unwrap(),
861            HeaderFormat::Type1LogHeader
862        );
863        assert_eq!(
864            test_struct.number_of_supported_log_type_descriptors(),
865            Some(25)
866        );
867        assert_eq!(test_struct.length_of_each_log_type_descriptor(), Some(2));
868
869        let type_descriptors = test_struct.type_descriptors().unwrap();
870        let mut iterator = type_descriptors.into_iter();
871        let first = iterator.next().unwrap();
872        assert_eq!(*first.log_type(), LogType::SingleBitEccMemoryError);
873    }
874}