@@ -4,7 +4,7 @@ use super::Revision;
4
4
use crate :: table:: boot:: MemoryDescriptor ;
5
5
use crate :: { CStr16 , Error , Result , Status , StatusExt } ;
6
6
use core:: fmt:: { self , Debug , Display , Formatter } ;
7
- use core:: mem:: MaybeUninit ;
7
+ use core:: mem:: { size_of , MaybeUninit } ;
8
8
use core:: ptr;
9
9
10
10
pub use uefi_raw:: capsule:: { CapsuleBlockDescriptor , CapsuleFlags , CapsuleHeader } ;
@@ -582,6 +582,69 @@ impl Display for Time {
582
582
}
583
583
}
584
584
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
+
585
648
/// Unique key for a variable.
586
649
#[ cfg( feature = "alloc" ) ]
587
650
#[ derive( Debug ) ]
@@ -651,3 +714,52 @@ pub struct CapsuleInfo {
651
714
/// The type of reset required for the capsule update.
652
715
pub reset_type : ResetType ,
653
716
}
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