From 7313fdf69c7e48fa8822c25da2531fe3424b60da Mon Sep 17 00:00:00 2001 From: andre-braga Date: Thu, 20 Jun 2024 13:50:05 +0000 Subject: [PATCH] uefi: Add TryFrom<&[u8]> for Time I am implementing a UEFI application which needs to convert part of a byte splice (returned by the variable runtime service) into a `Time`. I wanted to see if it was worth upstreaming, in case others might also need of it. --- uefi/CHANGELOG.md | 3 +- uefi/src/table/runtime.rs | 148 +++++++++++++++++++++++++++++++++++++- 2 files changed, 149 insertions(+), 2 deletions(-) diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index 07bbabc35..5e5356449 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -20,7 +20,8 @@ - `MemoryMap::as_raw` which provides raw access to the memory map. This is for example useful if you create your own Multiboot2 bootloader that embeds the EFI mmap in a Multiboot2 boot information structure. -- `Mode` is now `Copy` and `Clone` +- `Mode` is now `Copy` and `Clone`. +- Added `TryFrom<&[u8]>` for `Time`. ## Changed - `SystemTable::exit_boot_services` is now `unsafe`. See that method's diff --git a/uefi/src/table/runtime.rs b/uefi/src/table/runtime.rs index f5945ac4a..97674bc95 100644 --- a/uefi/src/table/runtime.rs +++ b/uefi/src/table/runtime.rs @@ -4,7 +4,7 @@ use super::Revision; use crate::table::boot::MemoryDescriptor; use crate::{CStr16, Error, Result, Status, StatusExt}; use core::fmt::{self, Debug, Display, Formatter}; -use core::mem::MaybeUninit; +use core::mem::{size_of, MaybeUninit}; use core::ptr; pub use uefi_raw::capsule::{CapsuleBlockDescriptor, CapsuleFlags, CapsuleHeader}; @@ -582,6 +582,69 @@ impl Display for Time { } } +/// Error returned from failing to convert a byte slice into a [`Time`]. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum TimeByteConversionError { + /// One or more fields of the converted [`Time`] is invalid. + InvalidFields(TimeError), + /// The byte slice is not large enough to hold a [`Time`]. + InvalidSize, +} + +impl Display for TimeByteConversionError { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Self::InvalidFields(error) => write!(f, "{error}"), + Self::InvalidSize => write!( + f, + "the byte slice is not large enough to hold a Time struct" + ), + } + } +} + +impl TryFrom<&[u8]> for Time { + type Error = TimeByteConversionError; + + fn try_from(bytes: &[u8]) -> core::result::Result { + if size_of::