Skip to content

Commit 264813a

Browse files
committed
uefi: 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 264813a

File tree

2 files changed

+55
-16
lines changed

2 files changed

+55
-16
lines changed

uefi/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
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 as an enum instead of a struct so that one can specify what field of `Time` is invalid. `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

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -371,19 +371,41 @@ 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;
374+
/// Error returned by [`Time`] methods if the specified field
375+
/// is outside of the valid range.
376+
#[allow(missing_docs)]
377+
#[derive(Debug)]
378+
pub enum TimeError {
379+
Year,
380+
Month,
381+
Day,
382+
Hour,
383+
Minute,
384+
Second,
385+
Nanosecond,
386+
Timezone,
387+
Daylight,
388+
}
377389

378390
impl Display for TimeError {
379391
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
380-
write!(f, "{self:?}")
392+
match self {
393+
Self::Year => write!(f, "year not within `1900..=9999`"),
394+
Self::Month => write!(f, "month not within `1..=12"),
395+
Self::Day => write!(f, "day not within `1..=31`"),
396+
Self::Hour => write!(f, "hour not within `0..=23`"),
397+
Self::Minute => write!(f, "minute not within `0..=59`"),
398+
Self::Second => write!(f, "second not within `0..=59`"),
399+
Self::Nanosecond => write!(f, "nanosecond not within `0..=999_999_999`"),
400+
Self::Timezone => write!(
401+
f,
402+
"time_zone not `Time::UNSPECIFIED_TIMEZONE` nor within `-1440..=1440`"
403+
),
404+
Self::Daylight => write!(f, "unknown bits set for daylight"),
405+
}
381406
}
382407
}
383408

384-
#[cfg(feature = "unstable")]
385-
impl core::error::Error for TimeError {}
386-
387409
impl Time {
388410
/// Unspecified Timezone/local time.
389411
const UNSPECIFIED_TIMEZONE: i16 = uefi_raw::time::Time::UNSPECIFIED_TIMEZONE;
@@ -404,11 +426,8 @@ impl Time {
404426
daylight: params.daylight,
405427
pad2: 0,
406428
});
407-
if time.is_valid() {
408-
Ok(time)
409-
} else {
410-
Err(TimeError)
411-
}
429+
430+
time.is_valid().map(|_| time)
412431
}
413432

414433
/// Create an invalid `Time` with all fields set to zero. This can
@@ -422,10 +441,29 @@ impl Time {
422441
Self(uefi_raw::time::Time::invalid())
423442
}
424443

425-
/// True if all fields are within valid ranges, false otherwise.
426-
#[must_use]
427-
pub fn is_valid(&self) -> bool {
428-
self.0.is_valid()
444+
/// `Ok()` if all fields are within valid ranges, `Err(TimeError)` otherwise.
445+
pub fn is_valid(&self) -> core::result::Result<(), TimeError> {
446+
if !(1900..=9999).contains(&self.year()) {
447+
Err(TimeError::Year)
448+
} else if !(1..=12).contains(&self.month()) {
449+
Err(TimeError::Month)
450+
} else if !(1..=31).contains(&self.day()) {
451+
Err(TimeError::Day)
452+
} else if self.hour() > 23 {
453+
Err(TimeError::Hour)
454+
} else if self.minute() > 59 {
455+
Err(TimeError::Minute)
456+
} else if self.second() > 59 {
457+
Err(TimeError::Second)
458+
} else if self.nanosecond() > 999_999_999 {
459+
Err(TimeError::Nanosecond)
460+
} else if self.time_zone().is_some()
461+
&& !((-1440..=1440).contains(&self.time_zone().unwrap()))
462+
{
463+
Err(TimeError::Timezone)
464+
} else {
465+
Ok(())
466+
}
429467
}
430468

431469
/// Query the year.

0 commit comments

Comments
 (0)