mirror of
https://github.com/rust-osdev/uefi-rs
synced 2026-06-08 17:17:36 +00:00
uefi: add time03 feature and integrate time types with struct Time
This commit is contained in:
Generated
+40
@@ -200,6 +200,15 @@ dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
@@ -486,6 +495,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
@@ -511,6 +526,12 @@ version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.37"
|
||||
@@ -862,6 +883,24 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca"
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "1.1.2+spec-1.1.0"
|
||||
@@ -940,6 +979,7 @@ dependencies = [
|
||||
"log",
|
||||
"ptr_meta",
|
||||
"qemu-exit",
|
||||
"time",
|
||||
"ucs2",
|
||||
"uefi-macros",
|
||||
"uefi-raw",
|
||||
|
||||
@@ -24,6 +24,7 @@ bitflags = "2.0.0"
|
||||
log = { version = "0.4.5", default-features = false }
|
||||
ptr_meta = { version = "0.3.0", default-features = false, features = ["derive"] }
|
||||
qemu-exit = { version = "4.0.0" }
|
||||
time = { version = "0.3", default-features = false }
|
||||
uguid = "2.2.1"
|
||||
|
||||
[patch.crates-io]
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
- Added `Serial::read_exact()` and `Serial::write_exact()`
|
||||
- `CStr16::from_bytes_with_nul()`: This is especially useful to transform the
|
||||
retrieved value from a UEFI variable into a UCS2 (CStr16) string.
|
||||
- Integration of `Time` with `time` crate
|
||||
- `TryFrom`: `time::PrimitiveDateTime <--> Time` (without timezone)
|
||||
- `TryFrom`: `time::OffsetDateTime <--> Time` (with timezone)
|
||||
|
||||
## Changed
|
||||
- export all `text::{input, output}::*` types
|
||||
|
||||
@@ -20,6 +20,8 @@ rust-version.workspace = true
|
||||
# KEEP this feature list in sync with doc in uefi/lib.rs!
|
||||
default = [ ]
|
||||
alloc = []
|
||||
# Integration with time crate `>= v0.3`
|
||||
time03 = ["dep:time"]
|
||||
|
||||
# Generic gate to code that uses unstable features of Rust, needing a nightly
|
||||
# toolchain.
|
||||
@@ -39,6 +41,7 @@ log-debugcon = []
|
||||
bitflags.workspace = true
|
||||
log.workspace = true
|
||||
ptr_meta.workspace = true
|
||||
time = { workspace = true, optional = true }
|
||||
qemu-exit = { workspace = true, optional = true }
|
||||
uguid.workspace = true
|
||||
cfg-if = "1.0.0"
|
||||
|
||||
@@ -148,6 +148,9 @@
|
||||
//! - `log-debugcon`: Whether the logger set up by `logger` should also log
|
||||
//! to the debugcon device (available in QEMU or Cloud Hypervisor on x86).
|
||||
//! - `panic_handler`: Add a default panic handler that logs to `stdout`.
|
||||
//! - `time03`: Integration of [`runtime::Time`] with the `time` crate
|
||||
//! (version 0.3 and possible above). Specifically, it integrates the time
|
||||
//! struct with `PrimitiveDateTime` and `OffsetDateTime` via `TryFrom`.
|
||||
//! - `unstable`: Enable functionality that depends on [unstable features] in
|
||||
//! the Rust compiler (nightly version).
|
||||
//! - `qemu`: Enable some code paths to adapt their execution when executed
|
||||
|
||||
@@ -40,6 +40,9 @@ pub(super) enum ConversionErrorInner {
|
||||
///
|
||||
/// [`Time::UNSPECIFIED_TIMEZONE`]: super::Time::UNSPECIFIED_TIMEZONE
|
||||
UnspecifiedTimezone,
|
||||
/// Errors raised in the [`time`] crate.
|
||||
#[cfg(feature = "time03")]
|
||||
TimeCrateError(time::Error),
|
||||
}
|
||||
|
||||
impl Display for ConversionErrorInner {
|
||||
@@ -48,6 +51,8 @@ impl Display for ConversionErrorInner {
|
||||
Self::InvalidComponent => write!(f, "Invalid component"),
|
||||
Self::InvalidUefiTime(e) => write!(f, "Invalid UEFI time: {e}"),
|
||||
Self::UnspecifiedTimezone => write!(f, "Unspecified timezone"),
|
||||
#[cfg(feature = "time03")]
|
||||
Self::TimeCrateError(e) => write!(f, "Time crate error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +63,8 @@ impl Error for ConversionErrorInner {
|
||||
Self::InvalidComponent => None,
|
||||
Self::InvalidUefiTime(e) => Some(e),
|
||||
Self::UnspecifiedTimezone => None,
|
||||
#[cfg(feature = "time03")]
|
||||
Self::TimeCrateError(e) => Some(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
//! Integration of the UEFI [`Time`] type with the [`time`] crate.
|
||||
|
||||
use super::Time;
|
||||
use super::integration_common::{ConversionError, ConversionErrorInner};
|
||||
use crate::runtime::TimeParams;
|
||||
use time::{OffsetDateTime, PrimitiveDateTime, UtcOffset};
|
||||
|
||||
impl TryFrom<Time> for PrimitiveDateTime {
|
||||
type Error = ConversionError;
|
||||
|
||||
fn try_from(value: Time) -> Result<Self, Self::Error> {
|
||||
if let Err(e) = value.is_valid() {
|
||||
return Err(ConversionError(ConversionErrorInner::InvalidUefiTime(e)));
|
||||
}
|
||||
|
||||
// Emulated try {} block to keep the `?` error propagation scoped
|
||||
// (we have a different error type here)
|
||||
let datetime: Result<Self, time::error::ComponentRange> = (|| {
|
||||
let month = time::Month::try_from(value.0.month)?;
|
||||
let date = time::Date::from_calendar_date(value.0.year as i32, month, value.0.day)?;
|
||||
let time = time::Time::from_hms_nano(
|
||||
value.0.hour,
|
||||
value.0.minute,
|
||||
value.0.second,
|
||||
value.0.nanosecond,
|
||||
)?;
|
||||
Ok(Self::new(date, time))
|
||||
})();
|
||||
|
||||
datetime
|
||||
.map_err(time::Error::ComponentRange)
|
||||
.map_err(|e| ConversionError(ConversionErrorInner::TimeCrateError(e)))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Time> for OffsetDateTime {
|
||||
type Error = ConversionError;
|
||||
|
||||
fn try_from(value: Time) -> Result<Self, Self::Error> {
|
||||
if let Err(e) = value.is_valid() {
|
||||
return Err(ConversionError(ConversionErrorInner::InvalidUefiTime(e)));
|
||||
}
|
||||
|
||||
let primitive_date_time: PrimitiveDateTime = value.try_into()?;
|
||||
|
||||
if value.0.time_zone == Time::UNSPECIFIED_TIMEZONE {
|
||||
return Err(ConversionError(ConversionErrorInner::UnspecifiedTimezone));
|
||||
}
|
||||
|
||||
let h = (value.0.time_zone / 60) as i8;
|
||||
let m = (value.0.time_zone.abs() % 60) as i8;
|
||||
|
||||
let offset = UtcOffset::from_hms(h, m, 0)
|
||||
.map_err(time::Error::ComponentRange)
|
||||
.map_err(|e| ConversionError(ConversionErrorInner::TimeCrateError(e)))?;
|
||||
Ok(primitive_date_time.assume_offset(offset))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<PrimitiveDateTime> for Time {
|
||||
type Error = ConversionError;
|
||||
|
||||
fn try_from(value: PrimitiveDateTime) -> Result<Self, Self::Error> {
|
||||
let params = TimeParams {
|
||||
year: u16::try_from(value.year())
|
||||
.map_err(|_e| ConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||
month: u8::from(value.month()),
|
||||
day: value.day(),
|
||||
hour: value.hour(),
|
||||
minute: value.minute(),
|
||||
second: value.second(),
|
||||
nanosecond: value.nanosecond(),
|
||||
time_zone: None,
|
||||
daylight: Default::default(),
|
||||
};
|
||||
Self::new(params).map_err(|e| ConversionError(ConversionErrorInner::InvalidUefiTime(e)))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<OffsetDateTime> for Time {
|
||||
type Error = ConversionError;
|
||||
|
||||
fn try_from(value: OffsetDateTime) -> Result<Self, Self::Error> {
|
||||
let timezone_offset_minutes = value.offset().whole_seconds() / 60;
|
||||
if value.offset().whole_seconds() % 60 != 0 {
|
||||
return Err(ConversionError(ConversionErrorInner::InvalidComponent));
|
||||
}
|
||||
|
||||
let params = TimeParams {
|
||||
year: u16::try_from(value.year())
|
||||
.map_err(|_e| ConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||
month: u8::from(value.month()),
|
||||
day: value.day(),
|
||||
hour: value.hour(),
|
||||
minute: value.minute(),
|
||||
second: value.second(),
|
||||
nanosecond: value.nanosecond(),
|
||||
time_zone: Some(
|
||||
i16::try_from(timezone_offset_minutes)
|
||||
.map_err(|_e| ConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||
),
|
||||
daylight: Default::default(),
|
||||
};
|
||||
|
||||
Self::new(params).map_err(|e| ConversionError(ConversionErrorInner::InvalidUefiTime(e)))
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,25 @@ use core::fmt;
|
||||
use core::fmt::{Debug, Display, Formatter};
|
||||
use uefi_raw::time::Daylight;
|
||||
|
||||
#[allow(unused)]
|
||||
#[cfg(feature = "time03")]
|
||||
mod integration_common;
|
||||
#[cfg(feature = "time03")]
|
||||
mod integration_time_crate;
|
||||
|
||||
/// Date and time representation.
|
||||
///
|
||||
/// # Integration with Time-related Crates of the Ecosystem
|
||||
///
|
||||
/// Handling time is complicated. Therefore, we do not reinvent the wheel and
|
||||
/// forward all complexity of time to well-known crates of the ecosystem. For
|
||||
/// that, we provide integrations with various crates:
|
||||
///
|
||||
/// ## Integration with [`time`][time crate] crate
|
||||
///
|
||||
/// - [`TryFrom`]: `PrimitiveDateTime` <--> [`Time`] (without timezone)
|
||||
/// - [`TryFrom`]: `OffsetDateTime` <--> [`Time`] (with timezone)
|
||||
///
|
||||
/// [time crate]: https://crates.io/crates/time
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
#[repr(transparent)]
|
||||
pub struct Time(uefi_raw::time::Time);
|
||||
|
||||
+7
-5
@@ -56,6 +56,7 @@ pub enum Feature {
|
||||
Unstable,
|
||||
PanicHandler,
|
||||
Qemu,
|
||||
Time03,
|
||||
|
||||
// `uefi-test-runner` features.
|
||||
DebugSupport,
|
||||
@@ -76,6 +77,7 @@ impl Feature {
|
||||
Self::Unstable => "unstable",
|
||||
Self::PanicHandler => "panic_handler",
|
||||
Self::Qemu => "qemu",
|
||||
Self::Time03 => "time03",
|
||||
|
||||
Self::DebugSupport => "uefi-test-runner/debug_support",
|
||||
Self::MultiProcessor => "uefi-test-runner/multi_processor",
|
||||
@@ -117,7 +119,7 @@ impl Feature {
|
||||
/// - `include_unstable` - add all functionality behind the `unstable` feature
|
||||
/// - `runtime_features` - add all functionality that effect the runtime of Rust
|
||||
pub fn more_code(include_unstable: bool, runtime_features: bool) -> Vec<Self> {
|
||||
let mut base_features = vec![Self::Alloc, Self::LogDebugcon, Self::Logger];
|
||||
let mut base_features = vec![Self::Alloc, Self::LogDebugcon, Self::Logger, Self::Time03];
|
||||
if include_unstable {
|
||||
base_features.extend([Self::Unstable])
|
||||
}
|
||||
@@ -387,19 +389,19 @@ mod tests {
|
||||
fn test_comma_separated_features() {
|
||||
assert_eq!(
|
||||
Feature::comma_separated_string(&Feature::more_code(false, false)),
|
||||
"alloc,log-debugcon,logger"
|
||||
"alloc,log-debugcon,logger,time03"
|
||||
);
|
||||
assert_eq!(
|
||||
Feature::comma_separated_string(&Feature::more_code(false, true)),
|
||||
"alloc,log-debugcon,logger,global_allocator"
|
||||
"alloc,log-debugcon,logger,time03,global_allocator"
|
||||
);
|
||||
assert_eq!(
|
||||
Feature::comma_separated_string(&Feature::more_code(true, false)),
|
||||
"alloc,log-debugcon,logger,unstable"
|
||||
"alloc,log-debugcon,logger,time03,unstable"
|
||||
);
|
||||
assert_eq!(
|
||||
Feature::comma_separated_string(&Feature::more_code(true, true)),
|
||||
"alloc,log-debugcon,logger,unstable,global_allocator"
|
||||
"alloc,log-debugcon,logger,time03,unstable,global_allocator"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user