@@ -4,7 +4,7 @@ use super::Revision;
44use crate :: table:: boot:: MemoryDescriptor ;
55use crate :: { CStr16 , Error , Result , Status , StatusExt } ;
66use core:: fmt:: { self , Debug , Display , Formatter } ;
7- use core:: mem:: MaybeUninit ;
7+ use core:: mem:: { size_of , MaybeUninit } ;
88use core:: ptr;
99
1010pub use uefi_raw:: capsule:: { CapsuleBlockDescriptor , CapsuleFlags , CapsuleHeader } ;
@@ -582,6 +582,69 @@ impl Display for Time {
582582 }
583583}
584584
585+ /// Error returned from failing to convert a byte splice into a [`Time`].
586+ #[ derive( Clone , Copy , Debug ) ]
587+ pub enum TimeByteConversionError {
588+ /// One or more fields of the converted [`Time`] is invalid.
589+ InvalidFields ( TimeError ) ,
590+ /// The byte splice is not large enough to hold a [`Time`].
591+ InvalidSize ,
592+ }
593+
594+ impl Display for TimeByteConversionError {
595+ fn fmt ( & self , f : & mut Formatter ) -> fmt:: Result {
596+ match self {
597+ Self :: InvalidFields ( error) => write ! ( f, "{error}" ) ,
598+ Self :: InvalidSize => write ! (
599+ f,
600+ "the byte splice is not large enough to hold a Time struct"
601+ ) ,
602+ }
603+ }
604+ }
605+
606+ impl TryFrom < & [ u8 ] > for Time {
607+ type Error = TimeByteConversionError ;
608+
609+ fn try_from ( bytes : & [ u8 ] ) -> core:: result:: Result < Self , Self :: Error > {
610+ if size_of :: < Time > ( ) <= bytes. len ( ) {
611+ let year = u16:: from_le_bytes ( bytes[ 0 ..2 ] . try_into ( ) . unwrap ( ) ) ;
612+ let month = bytes[ 2 ] ;
613+ let day = bytes[ 3 ] ;
614+ let hour = bytes[ 4 ] ;
615+ let minute = bytes[ 5 ] ;
616+ let second = bytes[ 6 ] ;
617+ let nanosecond = u32:: from_le_bytes ( bytes[ 8 ..12 ] . try_into ( ) . unwrap ( ) ) ;
618+ let time_zone = match i16:: from_le_bytes ( bytes[ 12 ..14 ] . try_into ( ) . unwrap ( ) ) {
619+ Self :: UNSPECIFIED_TIMEZONE => None ,
620+ num => Some ( num) ,
621+ } ;
622+ let daylight = Daylight :: from_bits ( bytes[ 14 ] ) . ok_or (
623+ TimeByteConversionError :: InvalidFields ( TimeError {
624+ daylight : true ,
625+ ..Default :: default ( )
626+ } ) ,
627+ ) ?;
628+
629+ let time_params = TimeParams {
630+ year,
631+ month,
632+ day,
633+ hour,
634+ minute,
635+ second,
636+ nanosecond,
637+ time_zone,
638+ daylight,
639+ } ;
640+
641+ Time :: new ( time_params) . map_err ( TimeByteConversionError :: InvalidFields )
642+ } else {
643+ Err ( TimeByteConversionError :: InvalidSize )
644+ }
645+ }
646+ }
647+
585648/// Unique key for a variable.
586649#[ cfg( feature = "alloc" ) ]
587650#[ derive( Debug ) ]
@@ -651,3 +714,52 @@ pub struct CapsuleInfo {
651714 /// The type of reset required for the capsule update.
652715 pub reset_type : ResetType ,
653716}
717+
718+ #[ cfg( test) ]
719+ mod tests {
720+ use super :: * ;
721+
722+ use alloc:: string:: ToString ;
723+ use core:: slice;
724+
725+ unsafe fn time_as_u8_slice ( p : & Time ) -> & [ u8 ] {
726+ slice:: from_raw_parts ( core:: ptr:: addr_of!( * p) . cast ( ) , size_of :: < Time > ( ) )
727+ }
728+
729+ #[ test]
730+ fn test_time_from_bytes ( ) {
731+ let mut time;
732+ let mut time_from_bytes;
733+ let mut time_params = TimeParams {
734+ year : 2024 ,
735+ month : 6 ,
736+ day : 13 ,
737+ hour : 4 ,
738+ minute : 29 ,
739+ second : 30 ,
740+ nanosecond : 123_456_789 ,
741+ time_zone : None ,
742+ daylight : Daylight :: empty ( ) ,
743+ } ;
744+
745+ time = Time :: new ( time_params) . unwrap ( ) ;
746+ unsafe {
747+ time_from_bytes = Time :: try_from ( time_as_u8_slice ( & time) ) . unwrap ( ) ;
748+ }
749+ assert_eq ! ( time, time_from_bytes) ;
750+
751+ time_params. time_zone = Some ( 120 ) ;
752+ time = Time :: new ( time_params) . unwrap ( ) ;
753+ unsafe {
754+ time_from_bytes = Time :: try_from ( time_as_u8_slice ( & time) ) . unwrap ( ) ;
755+ }
756+ assert_eq ! ( time. to_string( ) , time_from_bytes. to_string( ) ) ;
757+
758+ time_params. time_zone = Some ( 150 ) ;
759+ time = Time :: new ( time_params) . unwrap ( ) ;
760+ unsafe {
761+ time_from_bytes = Time :: try_from ( time_as_u8_slice ( & time) ) . unwrap ( ) ;
762+ }
763+ assert_eq ! ( time. to_string( ) , time_from_bytes. to_string( ) ) ;
764+ }
765+ }
0 commit comments