Skip to content

Commit a0c9d27

Browse files
committed
uefi-raw: Make TimeError more descriptive
When returning a TimeError, it'd be helpful to specify to the user which field is invalid so that it can be handled accordingly, or at least communicated. This change does this by reimplementing TimeError as an enum instead of a struct, allowing for specification and more verbose error display.
1 parent cfd63fb commit a0c9d27

File tree

4 files changed

+66
-34
lines changed

4 files changed

+66
-34
lines changed

uefi-raw/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Changed
44
- `maximum_capsule_size` of `query_capsule_capabilities` now takes a *mut u64 instead of a *mut usize.
55
- `ResetType` now derives the `Default` trait.
6+
- `TimeError` is now implemented in uefi-raw as an enum instead of a struct in uefi. One can now specify what field of `Time` is invalid, and `Time::is_valid` has been updated accordingly.
67

78
# uefi-raw - 0.5.2 (2024-04-19)
89

uefi-raw/src/time.rs

+59-12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,42 @@
33
use bitflags::bitflags;
44
use core::fmt::{self, Display, Formatter};
55

6+
newtype_enum! {
7+
/// Error returned by [`Time`] methods if the specified field
8+
/// is outside of the valid range.
9+
pub enum TimeError: u32 => {
10+
YEAR = 0,
11+
MONTH = 1,
12+
DAY = 2,
13+
HOUR = 3 ,
14+
MINUTE = 4 ,
15+
SECOND = 5,
16+
NANOSECOND = 6,
17+
TIMEZONE = 7 ,
18+
DAYLIGHT = 8,
19+
}
20+
}
21+
22+
impl Display for TimeError {
23+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
24+
match *self {
25+
Self::YEAR => write!(f, "year not within `1900..=9999`"),
26+
Self::MONTH => write!(f, "month not within `1..=12"),
27+
Self::DAY => write!(f, "day not within `1..=31`"),
28+
Self::HOUR => write!(f, "hour not within `0..=23`"),
29+
Self::MINUTE => write!(f, "minute not within `0..=59`"),
30+
Self::SECOND => write!(f, "second not within `0..=59`"),
31+
Self::NANOSECOND => write!(f, "nanosecond not within `0..=999_999_999`"),
32+
Self::TIMEZONE => write!(
33+
f,
34+
"time_zone not `Time::UNSPECIFIED_TIMEZONE` nor within `-1440..=1440`"
35+
),
36+
Self::DAYLIGHT => write!(f, "unknown bits set for daylight"),
37+
Self(9_u32..=u32::MAX) => panic!(),
38+
}
39+
}
40+
}
41+
642
/// Date and time representation.
743
#[derive(Debug, Default, Copy, Clone, Eq)]
844
#[repr(C)]
@@ -64,18 +100,29 @@ impl Time {
64100
}
65101
}
66102

67-
/// True if all fields are within valid ranges, false otherwise.
68-
#[must_use]
69-
pub fn is_valid(&self) -> bool {
70-
(1900..=9999).contains(&self.year)
71-
&& (1..=12).contains(&self.month)
72-
&& (1..=31).contains(&self.day)
73-
&& self.hour <= 23
74-
&& self.minute <= 59
75-
&& self.second <= 59
76-
&& self.nanosecond <= 999_999_999
77-
&& ((-1440..=1440).contains(&self.time_zone)
78-
|| self.time_zone == Self::UNSPECIFIED_TIMEZONE)
103+
/// `Ok()` if all fields are within valid ranges, `Err(TimeError)` otherwise.
104+
pub fn is_valid(&self) -> Result<(), TimeError> {
105+
if !(1900..=9999).contains(&self.year) {
106+
Err(TimeError::YEAR)
107+
} else if !(1..=12).contains(&self.month) {
108+
Err(TimeError::MONTH)
109+
} else if !(1..=31).contains(&self.day) {
110+
Err(TimeError::DAY)
111+
} else if self.hour > 23 {
112+
Err(TimeError::HOUR)
113+
} else if self.minute > 59 {
114+
Err(TimeError::MINUTE)
115+
} else if self.second > 59 {
116+
Err(TimeError::SECOND)
117+
} else if self.nanosecond > 999_999_999 {
118+
Err(TimeError::NANOSECOND)
119+
} else if !((-1440..=1440).contains(&self.time_zone)
120+
|| self.time_zone == Self::UNSPECIFIED_TIMEZONE)
121+
{
122+
Err(TimeError::TIMEZONE)
123+
} else {
124+
Ok(())
125+
}
79126
}
80127
}
81128

uefi/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- Added `TryFrom<&[u8]>` for `DevicePathHeader`, `DevicePathNode` and `DevicePath`.
1515
- Added `ByteConversionError`.
1616
- Re-exported `CapsuleFlags`.
17+
- `TimeError` is now implemented in uefi-raw as an enum instead of a struct in uefi. One can now specify what field of `Time` is invalid, and `Time::is_valid` has been updated accordingly.
1718

1819
## Changed
1920
- `SystemTable::exit_boot_services` is now `unsafe`. See that method's

uefi/src/table/runtime.rs

+5-22
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub use uefi_raw::capsule::{CapsuleBlockDescriptor, CapsuleFlags, CapsuleHeader}
1111
pub use uefi_raw::table::runtime::{
1212
ResetType, TimeCapabilities, VariableAttributes, VariableVendor,
1313
};
14-
pub use uefi_raw::time::Daylight;
14+
pub use uefi_raw::time::{Daylight, TimeError};
1515
pub use uefi_raw::PhysicalAddress;
1616

1717
#[cfg(feature = "alloc")]
@@ -371,19 +371,6 @@ pub struct TimeParams {
371371
pub daylight: Daylight,
372372
}
373373

374-
/// Error returned by [`Time`] methods if the input is outside the valid range.
375-
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
376-
pub struct TimeError;
377-
378-
impl Display for TimeError {
379-
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
380-
write!(f, "{self:?}")
381-
}
382-
}
383-
384-
#[cfg(feature = "unstable")]
385-
impl core::error::Error for TimeError {}
386-
387374
impl Time {
388375
/// Unspecified Timezone/local time.
389376
const UNSPECIFIED_TIMEZONE: i16 = uefi_raw::time::Time::UNSPECIFIED_TIMEZONE;
@@ -404,11 +391,8 @@ impl Time {
404391
daylight: params.daylight,
405392
pad2: 0,
406393
});
407-
if time.is_valid() {
408-
Ok(time)
409-
} else {
410-
Err(TimeError)
411-
}
394+
395+
time.is_valid().map(|_| time)
412396
}
413397

414398
/// Create an invalid `Time` with all fields set to zero. This can
@@ -422,9 +406,8 @@ impl Time {
422406
Self(uefi_raw::time::Time::invalid())
423407
}
424408

425-
/// True if all fields are within valid ranges, false otherwise.
426-
#[must_use]
427-
pub fn is_valid(&self) -> bool {
409+
/// `Ok()` if all fields are within valid ranges, `Err(TimeError)` otherwise.
410+
pub fn is_valid(&self) -> core::result::Result<(), TimeError> {
428411
self.0.is_valid()
429412
}
430413

0 commit comments

Comments
 (0)