mirror of
https://github.com/rust-osdev/uefi-rs
synced 2026-08-26 18:26:05 -04:00
uefi: add jiff02 feature and integrate jiff types with struct Time
This commit is contained in:
parent
da39859044
commit
afdd47bf40
9 changed files with 204 additions and 6 deletions
38
Cargo.lock
generated
38
Cargo.lock
generated
|
|
@ -435,6 +435,28 @@ version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jiff"
|
||||||
|
version = "0.2.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359"
|
||||||
|
dependencies = [
|
||||||
|
"jiff-static",
|
||||||
|
"portable-atomic",
|
||||||
|
"portable-atomic-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jiff-static"
|
||||||
|
version = "0.2.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "leb128fmt"
|
name = "leb128fmt"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
@ -538,6 +560,21 @@ version = "2.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "portable-atomic"
|
||||||
|
version = "1.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "portable-atomic-util"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3"
|
||||||
|
dependencies = [
|
||||||
|
"portable-atomic",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "powerfmt"
|
name = "powerfmt"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
@ -988,6 +1025,7 @@ version = "0.37.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.1",
|
"bitflags 2.11.1",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"jiff",
|
||||||
"log",
|
"log",
|
||||||
"ptr_meta",
|
"ptr_meta",
|
||||||
"qemu-exit",
|
"qemu-exit",
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ rust-version = "1.91"
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
bitflags = "2.0.0"
|
bitflags = "2.0.0"
|
||||||
log = { version = "0.4.5", default-features = false }
|
log = { version = "0.4.5", default-features = false }
|
||||||
|
jiff = { version = "0.2", default-features = false }
|
||||||
ptr_meta = { version = "0.3.0", default-features = false, features = ["derive"] }
|
ptr_meta = { version = "0.3.0", default-features = false, features = ["derive"] }
|
||||||
qemu-exit = { version = "4.0.0" }
|
qemu-exit = { version = "4.0.0" }
|
||||||
time = { version = "0.3", default-features = false }
|
time = { version = "0.3", default-features = false }
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,9 @@
|
||||||
- Integration of `Time` with `time` crate
|
- Integration of `Time` with `time` crate
|
||||||
- `TryFrom`: `time::PrimitiveDateTime <--> Time` (without timezone)
|
- `TryFrom`: `time::PrimitiveDateTime <--> Time` (without timezone)
|
||||||
- `TryFrom`: `time::OffsetDateTime <--> Time` (with timezone)
|
- `TryFrom`: `time::OffsetDateTime <--> Time` (with timezone)
|
||||||
|
- Integration of `Time` with `jiff` crate
|
||||||
|
- `TryFrom`: `jiff::DateTime <--> Time` (without timezone)
|
||||||
|
- `TryFrom`: `jiff::Zoned <--> Time` (with timezone)
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
- export all `text::{input, output}::*` types
|
- 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!
|
# KEEP this feature list in sync with doc in uefi/lib.rs!
|
||||||
default = [ ]
|
default = [ ]
|
||||||
alloc = []
|
alloc = []
|
||||||
|
# Integration with jiff crate `v0.2`
|
||||||
|
jiff02 = ["dep:jiff"]
|
||||||
# Integration with time crate `v0.3`
|
# Integration with time crate `v0.3`
|
||||||
time03 = ["dep:time"]
|
time03 = ["dep:time"]
|
||||||
|
|
||||||
|
|
@ -41,6 +43,7 @@ log-debugcon = []
|
||||||
bitflags.workspace = true
|
bitflags.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
ptr_meta.workspace = true
|
ptr_meta.workspace = true
|
||||||
|
jiff = { workspace = true, optional = true }
|
||||||
time = { workspace = true, optional = true }
|
time = { workspace = true, optional = true }
|
||||||
qemu-exit = { workspace = true, optional = true }
|
qemu-exit = { workspace = true, optional = true }
|
||||||
uguid.workspace = true
|
uguid.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,9 @@
|
||||||
//! using this feature, or no allocator at all if you don't need to
|
//! using this feature, or no allocator at all if you don't need to
|
||||||
//! dynamically allocate any memory. Note that even without that feature,
|
//! dynamically allocate any memory. Note that even without that feature,
|
||||||
//! some code might use the internal UEFI allocator.
|
//! some code might use the internal UEFI allocator.
|
||||||
|
//! - `jiff02`: Integration of [`runtime::Time`] with the `jiff` crate
|
||||||
|
//! (version 0.2 and possible above). Specifically, it integrates the time
|
||||||
|
//! struct with `DateTime` and `Zoned` via `TryFrom`.
|
||||||
//! - `logger`: Logging implementation for the standard [`log`] crate
|
//! - `logger`: Logging implementation for the standard [`log`] crate
|
||||||
//! that prints output to the UEFI console. No buffering is done; this
|
//! that prints output to the UEFI console. No buffering is done; this
|
||||||
//! is not a high-performance logger.
|
//! is not a high-performance logger.
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,9 @@ pub(super) enum ConversionErrorInner {
|
||||||
/// Errors raised in the [`time`] crate.
|
/// Errors raised in the [`time`] crate.
|
||||||
#[cfg(feature = "time03")]
|
#[cfg(feature = "time03")]
|
||||||
TimeCrateError(time::Error),
|
TimeCrateError(time::Error),
|
||||||
|
/// Errors raised in the [`jiff`] crate.
|
||||||
|
#[cfg(feature = "jiff02")]
|
||||||
|
JiffCrateError(jiff::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ConversionErrorInner {
|
impl Display for ConversionErrorInner {
|
||||||
|
|
@ -48,6 +51,8 @@ impl Display for ConversionErrorInner {
|
||||||
Self::UnspecifiedTimezone => write!(f, "Unspecified timezone"),
|
Self::UnspecifiedTimezone => write!(f, "Unspecified timezone"),
|
||||||
#[cfg(feature = "time03")]
|
#[cfg(feature = "time03")]
|
||||||
Self::TimeCrateError(e) => write!(f, "Time crate error: {}", e),
|
Self::TimeCrateError(e) => write!(f, "Time crate error: {}", e),
|
||||||
|
#[cfg(feature = "jiff02")]
|
||||||
|
Self::JiffCrateError(e) => write!(f, "Jiff crate error: {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -60,6 +65,9 @@ impl Error for ConversionErrorInner {
|
||||||
Self::UnspecifiedTimezone => None,
|
Self::UnspecifiedTimezone => None,
|
||||||
#[cfg(feature = "time03")]
|
#[cfg(feature = "time03")]
|
||||||
Self::TimeCrateError(e) => Some(e),
|
Self::TimeCrateError(e) => Some(e),
|
||||||
|
// None: Missing Error trait
|
||||||
|
#[cfg(feature = "jiff02")]
|
||||||
|
Self::JiffCrateError(_e) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
126
uefi/src/runtime/time/integration_jiff_crate.rs
Normal file
126
uefi/src/runtime/time/integration_jiff_crate.rs
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
|
//! Integration of the UEFI [`Time`] type with the [`jiff`] crate.
|
||||||
|
|
||||||
|
use super::Time;
|
||||||
|
use super::integration_common::{ConversionErrorInner, TimeConversionError};
|
||||||
|
use jiff::Zoned;
|
||||||
|
use jiff::civil::DateTime;
|
||||||
|
use jiff::tz::{Offset, TimeZone};
|
||||||
|
use uefi::runtime::TimeParams;
|
||||||
|
|
||||||
|
// Timezone unaware
|
||||||
|
impl TryFrom<Time> for DateTime {
|
||||||
|
type Error = TimeConversionError;
|
||||||
|
|
||||||
|
fn try_from(value: Time) -> Result<Self, Self::Error> {
|
||||||
|
if let Err(e) = value.is_valid() {
|
||||||
|
return Err(TimeConversionError(ConversionErrorInner::InvalidUefiTime(
|
||||||
|
e,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let datetime = Self::new(
|
||||||
|
// Cannot fail as the value is valid and in range (we checked that).
|
||||||
|
i16::try_from(value.0.year).unwrap(),
|
||||||
|
// Cannot fail as the value is valid and in range (we checked that).
|
||||||
|
i8::try_from(value.0.month).unwrap(),
|
||||||
|
// Cannot fail as the value is valid and in range (we checked that).
|
||||||
|
i8::try_from(value.0.day).unwrap(),
|
||||||
|
// Cannot fail as the value is valid and in range (we checked that).
|
||||||
|
i8::try_from(value.0.hour).unwrap(),
|
||||||
|
// Cannot fail as the value is valid and in range (we checked that).
|
||||||
|
i8::try_from(value.0.minute).unwrap(),
|
||||||
|
// Cannot fail as the value is valid and in range (we checked that).
|
||||||
|
i8::try_from(value.0.second).unwrap(),
|
||||||
|
// Cannot fail as the value is valid and in range (we checked that).
|
||||||
|
i32::try_from(value.0.nanosecond).unwrap(),
|
||||||
|
)
|
||||||
|
.map_err(|e| TimeConversionError(ConversionErrorInner::JiffCrateError(e)))?;
|
||||||
|
|
||||||
|
Ok(datetime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timezone aware
|
||||||
|
impl TryFrom<Time> for Zoned {
|
||||||
|
type Error = TimeConversionError;
|
||||||
|
|
||||||
|
fn try_from(value: Time) -> Result<Self, Self::Error> {
|
||||||
|
if let Err(e) = value.is_valid() {
|
||||||
|
return Err(TimeConversionError(ConversionErrorInner::InvalidUefiTime(
|
||||||
|
e,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.0.time_zone == Time::UNSPECIFIED_TIMEZONE {
|
||||||
|
return Err(TimeConversionError(
|
||||||
|
ConversionErrorInner::UnspecifiedTimezone,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let datetime = DateTime::try_from(value)?;
|
||||||
|
let seconds = value.0.time_zone as i32 * 60 /* seconds per minute */;
|
||||||
|
let offset = Offset::from_seconds(seconds)
|
||||||
|
.map_err(|e| TimeConversionError(ConversionErrorInner::JiffCrateError(e)))?;
|
||||||
|
let timezone = TimeZone::fixed(offset);
|
||||||
|
let zoned = datetime
|
||||||
|
.to_zoned(timezone)
|
||||||
|
.map_err(|e| TimeConversionError(ConversionErrorInner::JiffCrateError(e)))?;
|
||||||
|
Ok(zoned)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<DateTime> for Time {
|
||||||
|
type Error = TimeConversionError;
|
||||||
|
|
||||||
|
fn try_from(value: DateTime) -> Result<Self, Self::Error> {
|
||||||
|
let params = TimeParams {
|
||||||
|
year: u16::try_from(value.year())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
month: u8::try_from(value.month())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
day: u8::try_from(value.day())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
hour: u8::try_from(value.hour())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
minute: u8::try_from(value.minute())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
second: u8::try_from(value.second())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
nanosecond: u32::try_from(value.subsec_nanosecond())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
time_zone: None,
|
||||||
|
daylight: Default::default(),
|
||||||
|
};
|
||||||
|
Self::new(params).map_err(|e| TimeConversionError(ConversionErrorInner::InvalidUefiTime(e)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Zoned> for Time {
|
||||||
|
type Error = TimeConversionError;
|
||||||
|
fn try_from(value: Zoned) -> Result<Self, Self::Error> {
|
||||||
|
let params = TimeParams {
|
||||||
|
year: u16::try_from(value.year())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
month: u8::try_from(value.month())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
day: u8::try_from(value.day())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
hour: u8::try_from(value.hour())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
minute: u8::try_from(value.minute())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
second: u8::try_from(value.second())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
nanosecond: u32::try_from(value.subsec_nanosecond())
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
time_zone: Some(
|
||||||
|
i16::try_from(value.offset().seconds() / 60 /* seconds per minute */)
|
||||||
|
.map_err(|_e| TimeConversionError(ConversionErrorInner::InvalidComponent))?,
|
||||||
|
),
|
||||||
|
daylight: Default::default(),
|
||||||
|
};
|
||||||
|
Self::new(params).map_err(|e| TimeConversionError(ConversionErrorInner::InvalidUefiTime(e)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,8 +10,10 @@ use core::fmt;
|
||||||
use core::fmt::{Debug, Display, Formatter};
|
use core::fmt::{Debug, Display, Formatter};
|
||||||
use uefi_raw::time::Daylight;
|
use uefi_raw::time::Daylight;
|
||||||
|
|
||||||
#[cfg(feature = "time03")]
|
#[cfg(any(feature = "jiff02", feature = "time03"))]
|
||||||
mod integration_common;
|
mod integration_common;
|
||||||
|
#[cfg(feature = "jiff02")]
|
||||||
|
mod integration_jiff_crate;
|
||||||
#[cfg(feature = "time03")]
|
#[cfg(feature = "time03")]
|
||||||
mod integration_time_crate;
|
mod integration_time_crate;
|
||||||
|
|
||||||
|
|
@ -28,7 +30,13 @@ mod integration_time_crate;
|
||||||
/// - [`TryFrom`]: `PrimitiveDateTime` <--> [`Time`] (without timezone)
|
/// - [`TryFrom`]: `PrimitiveDateTime` <--> [`Time`] (without timezone)
|
||||||
/// - [`TryFrom`]: `OffsetDateTime` <--> [`Time`] (with timezone)
|
/// - [`TryFrom`]: `OffsetDateTime` <--> [`Time`] (with timezone)
|
||||||
///
|
///
|
||||||
|
/// ## Integration with [`jiff`][jiff crate] crate
|
||||||
|
///
|
||||||
|
/// - [`TryFrom`]: `DateTime` <--> [`Time`] (without timezone)
|
||||||
|
/// - [`TryFrom`]: `Zoned` <--> [`Time`] (with timezone)
|
||||||
|
///
|
||||||
/// [time crate]: https://crates.io/crates/time
|
/// [time crate]: https://crates.io/crates/time
|
||||||
|
/// [jiff crate]: https://crates.io/crates/jiff
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct Time(uefi_raw::time::Time);
|
pub struct Time(uefi_raw::time::Time);
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ pub enum Feature {
|
||||||
Unstable,
|
Unstable,
|
||||||
PanicHandler,
|
PanicHandler,
|
||||||
Qemu,
|
Qemu,
|
||||||
|
Jiff02,
|
||||||
Time03,
|
Time03,
|
||||||
|
|
||||||
// `uefi-test-runner` features.
|
// `uefi-test-runner` features.
|
||||||
|
|
@ -77,6 +78,7 @@ impl Feature {
|
||||||
Self::Unstable => "unstable",
|
Self::Unstable => "unstable",
|
||||||
Self::PanicHandler => "panic_handler",
|
Self::PanicHandler => "panic_handler",
|
||||||
Self::Qemu => "qemu",
|
Self::Qemu => "qemu",
|
||||||
|
Self::Jiff02 => "jiff02",
|
||||||
Self::Time03 => "time03",
|
Self::Time03 => "time03",
|
||||||
|
|
||||||
Self::DebugSupport => "uefi-test-runner/debug_support",
|
Self::DebugSupport => "uefi-test-runner/debug_support",
|
||||||
|
|
@ -119,7 +121,13 @@ impl Feature {
|
||||||
/// - `include_unstable` - add all functionality behind the `unstable` feature
|
/// - `include_unstable` - add all functionality behind the `unstable` feature
|
||||||
/// - `runtime_features` - add all functionality that effect the runtime of Rust
|
/// - `runtime_features` - add all functionality that effect the runtime of Rust
|
||||||
pub fn more_code(include_unstable: bool, runtime_features: bool) -> Vec<Self> {
|
pub fn more_code(include_unstable: bool, runtime_features: bool) -> Vec<Self> {
|
||||||
let mut base_features = vec![Self::Alloc, Self::LogDebugcon, Self::Logger, Self::Time03];
|
let mut base_features = vec![
|
||||||
|
Self::Alloc,
|
||||||
|
Self::Jiff02,
|
||||||
|
Self::LogDebugcon,
|
||||||
|
Self::Logger,
|
||||||
|
Self::Time03,
|
||||||
|
];
|
||||||
if include_unstable {
|
if include_unstable {
|
||||||
base_features.extend([Self::Unstable])
|
base_features.extend([Self::Unstable])
|
||||||
}
|
}
|
||||||
|
|
@ -389,19 +397,19 @@ mod tests {
|
||||||
fn test_comma_separated_features() {
|
fn test_comma_separated_features() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Feature::comma_separated_string(&Feature::more_code(false, false)),
|
Feature::comma_separated_string(&Feature::more_code(false, false)),
|
||||||
"alloc,log-debugcon,logger,time03"
|
"alloc,jiff02,log-debugcon,logger,time03"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Feature::comma_separated_string(&Feature::more_code(false, true)),
|
Feature::comma_separated_string(&Feature::more_code(false, true)),
|
||||||
"alloc,log-debugcon,logger,time03,global_allocator"
|
"alloc,jiff02,log-debugcon,logger,time03,global_allocator"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Feature::comma_separated_string(&Feature::more_code(true, false)),
|
Feature::comma_separated_string(&Feature::more_code(true, false)),
|
||||||
"alloc,log-debugcon,logger,time03,unstable"
|
"alloc,jiff02,log-debugcon,logger,time03,unstable"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Feature::comma_separated_string(&Feature::more_code(true, true)),
|
Feature::comma_separated_string(&Feature::more_code(true, true)),
|
||||||
"alloc,log-debugcon,logger,time03,unstable,global_allocator"
|
"alloc,jiff02,log-debugcon,logger,time03,unstable,global_allocator"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue