|
7 | 7 | //! functions after exiting boot services; see the "Calling Convention" section |
8 | 8 | //! of the UEFI specification for details. |
9 | 9 |
|
| 10 | +mod time_defs; |
| 11 | + |
| 12 | +pub use time_defs::{Time, TimeByteConversionError, TimeError, TimeParams}; |
| 13 | + |
10 | 14 | use crate::data_types::PhysicalAddress; |
11 | 15 | use crate::table::{self, Revision}; |
12 | 16 | use crate::{CStr16, Error, Result, Status, StatusExt}; |
13 | | -use core::fmt::{self, Debug, Display, Formatter}; |
| 17 | +use core::fmt::Debug; |
| 18 | +#[cfg(feature = "alloc")] |
| 19 | +use core::fmt::{self, Display, Formatter}; |
14 | 20 | use core::ptr::{self, NonNull}; |
15 | 21 | use uefi_raw::table::boot::MemoryDescriptor; |
16 | 22 |
|
@@ -549,317 +555,6 @@ pub unsafe fn set_virtual_address_map( |
549 | 555 | Ok(()) |
550 | 556 | } |
551 | 557 |
|
552 | | -/// Date and time representation. |
553 | | -#[derive(Copy, Clone, Eq, PartialEq)] |
554 | | -#[repr(transparent)] |
555 | | -pub struct Time(uefi_raw::time::Time); |
556 | | - |
557 | | -/// Input parameters for [`Time::new`]. |
558 | | -#[derive(Copy, Clone, Debug)] |
559 | | -pub struct TimeParams { |
560 | | - /// Year in the range `1900..=9999`. |
561 | | - pub year: u16, |
562 | | - |
563 | | - /// Month in the range `1..=12`. |
564 | | - pub month: u8, |
565 | | - |
566 | | - /// Day in the range `1..=31`. |
567 | | - pub day: u8, |
568 | | - |
569 | | - /// Hour in the range `0.=23`. |
570 | | - pub hour: u8, |
571 | | - |
572 | | - /// Minute in the range `0..=59`. |
573 | | - pub minute: u8, |
574 | | - |
575 | | - /// Second in the range `0..=59`. |
576 | | - pub second: u8, |
577 | | - |
578 | | - /// Fraction of a second represented as nanoseconds in the range |
579 | | - /// `0..=999_999_999`. |
580 | | - pub nanosecond: u32, |
581 | | - |
582 | | - /// Offset in minutes from UTC in the range `-1440..=1440`, or |
583 | | - /// local time if `None`. |
584 | | - pub time_zone: Option<i16>, |
585 | | - |
586 | | - /// Daylight savings time information. |
587 | | - pub daylight: Daylight, |
588 | | -} |
589 | | - |
590 | | -/// Error returned by [`Time`] methods. A bool value of `true` means |
591 | | -/// the specified field is outside its valid range. |
592 | | -#[allow(missing_docs)] |
593 | | -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] |
594 | | -pub struct TimeError { |
595 | | - pub year: bool, |
596 | | - pub month: bool, |
597 | | - pub day: bool, |
598 | | - pub hour: bool, |
599 | | - pub minute: bool, |
600 | | - pub second: bool, |
601 | | - pub nanosecond: bool, |
602 | | - pub timezone: bool, |
603 | | - pub daylight: bool, |
604 | | -} |
605 | | - |
606 | | -impl core::error::Error for TimeError {} |
607 | | - |
608 | | -impl Display for TimeError { |
609 | | - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
610 | | - if self.year { |
611 | | - writeln!(f, "year not within `1900..=9999`")?; |
612 | | - } |
613 | | - if self.month { |
614 | | - writeln!(f, "month not within `1..=12")?; |
615 | | - } |
616 | | - if self.day { |
617 | | - writeln!(f, "day not within `1..=31`")?; |
618 | | - } |
619 | | - if self.hour { |
620 | | - writeln!(f, "hour not within `0..=23`")?; |
621 | | - } |
622 | | - if self.minute { |
623 | | - writeln!(f, "minute not within `0..=59`")?; |
624 | | - } |
625 | | - if self.second { |
626 | | - writeln!(f, "second not within `0..=59`")?; |
627 | | - } |
628 | | - if self.nanosecond { |
629 | | - writeln!(f, "nanosecond not within `0..=999_999_999`")?; |
630 | | - } |
631 | | - if self.timezone { |
632 | | - writeln!( |
633 | | - f, |
634 | | - "time_zone not `Time::UNSPECIFIED_TIMEZONE` nor within `-1440..=1440`" |
635 | | - )?; |
636 | | - } |
637 | | - if self.daylight { |
638 | | - writeln!(f, "unknown bits set for daylight")?; |
639 | | - } |
640 | | - Ok(()) |
641 | | - } |
642 | | -} |
643 | | - |
644 | | -impl Time { |
645 | | - /// Unspecified Timezone/local time. |
646 | | - const UNSPECIFIED_TIMEZONE: i16 = uefi_raw::time::Time::UNSPECIFIED_TIMEZONE; |
647 | | - |
648 | | - /// Create a `Time` value. If a field is not in the valid range, |
649 | | - /// [`TimeError`] is returned. |
650 | | - pub fn new(params: TimeParams) -> core::result::Result<Self, TimeError> { |
651 | | - let time = Self(uefi_raw::time::Time { |
652 | | - year: params.year, |
653 | | - month: params.month, |
654 | | - day: params.day, |
655 | | - hour: params.hour, |
656 | | - minute: params.minute, |
657 | | - second: params.second, |
658 | | - pad1: 0, |
659 | | - nanosecond: params.nanosecond, |
660 | | - time_zone: params.time_zone.unwrap_or(Self::UNSPECIFIED_TIMEZONE), |
661 | | - daylight: params.daylight, |
662 | | - pad2: 0, |
663 | | - }); |
664 | | - |
665 | | - time.is_valid().map(|_| time) |
666 | | - } |
667 | | - |
668 | | - /// Create an invalid `Time` with all fields set to zero. This can |
669 | | - /// be used with [`FileInfo`] to indicate a field should not be |
670 | | - /// updated when calling [`File::set_info`]. |
671 | | - /// |
672 | | - /// [`FileInfo`]: uefi::proto::media::file::FileInfo |
673 | | - /// [`File::set_info`]: uefi::proto::media::file::File::set_info |
674 | | - #[must_use] |
675 | | - pub const fn invalid() -> Self { |
676 | | - Self(uefi_raw::time::Time::invalid()) |
677 | | - } |
678 | | - |
679 | | - /// `Ok()` if all fields are within valid ranges, `Err(TimeError)` otherwise. |
680 | | - pub fn is_valid(&self) -> core::result::Result<(), TimeError> { |
681 | | - let mut err = TimeError::default(); |
682 | | - if !(1900..=9999).contains(&self.year()) { |
683 | | - err.year = true; |
684 | | - } |
685 | | - if !(1..=12).contains(&self.month()) { |
686 | | - err.month = true; |
687 | | - } |
688 | | - if !(1..=31).contains(&self.day()) { |
689 | | - err.day = true; |
690 | | - } |
691 | | - if self.hour() > 23 { |
692 | | - err.hour = true; |
693 | | - } |
694 | | - if self.minute() > 59 { |
695 | | - err.minute = true; |
696 | | - } |
697 | | - if self.second() > 59 { |
698 | | - err.second = true; |
699 | | - } |
700 | | - if self.nanosecond() > 999_999_999 { |
701 | | - err.nanosecond = true; |
702 | | - } |
703 | | - if self.time_zone().is_some() && !((-1440..=1440).contains(&self.time_zone().unwrap())) { |
704 | | - err.timezone = true; |
705 | | - } |
706 | | - // All fields are false, i.e., within their valid range. |
707 | | - if err == TimeError::default() { |
708 | | - Ok(()) |
709 | | - } else { |
710 | | - Err(err) |
711 | | - } |
712 | | - } |
713 | | - |
714 | | - /// Query the year. |
715 | | - #[must_use] |
716 | | - pub const fn year(&self) -> u16 { |
717 | | - self.0.year |
718 | | - } |
719 | | - |
720 | | - /// Query the month. |
721 | | - #[must_use] |
722 | | - pub const fn month(&self) -> u8 { |
723 | | - self.0.month |
724 | | - } |
725 | | - |
726 | | - /// Query the day. |
727 | | - #[must_use] |
728 | | - pub const fn day(&self) -> u8 { |
729 | | - self.0.day |
730 | | - } |
731 | | - |
732 | | - /// Query the hour. |
733 | | - #[must_use] |
734 | | - pub const fn hour(&self) -> u8 { |
735 | | - self.0.hour |
736 | | - } |
737 | | - |
738 | | - /// Query the minute. |
739 | | - #[must_use] |
740 | | - pub const fn minute(&self) -> u8 { |
741 | | - self.0.minute |
742 | | - } |
743 | | - |
744 | | - /// Query the second. |
745 | | - #[must_use] |
746 | | - pub const fn second(&self) -> u8 { |
747 | | - self.0.second |
748 | | - } |
749 | | - |
750 | | - /// Query the nanosecond. |
751 | | - #[must_use] |
752 | | - pub const fn nanosecond(&self) -> u32 { |
753 | | - self.0.nanosecond |
754 | | - } |
755 | | - |
756 | | - /// Query the time offset in minutes from UTC, or None if using local time. |
757 | | - #[must_use] |
758 | | - pub const fn time_zone(&self) -> Option<i16> { |
759 | | - if self.0.time_zone == Self::UNSPECIFIED_TIMEZONE { |
760 | | - None |
761 | | - } else { |
762 | | - Some(self.0.time_zone) |
763 | | - } |
764 | | - } |
765 | | - |
766 | | - /// Query the daylight savings time information. |
767 | | - #[must_use] |
768 | | - pub const fn daylight(&self) -> Daylight { |
769 | | - self.0.daylight |
770 | | - } |
771 | | -} |
772 | | - |
773 | | -impl Debug for Time { |
774 | | - fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
775 | | - write!( |
776 | | - f, |
777 | | - "{:04}-{:02}-{:02} ", |
778 | | - self.0.year, self.0.month, self.0.day |
779 | | - )?; |
780 | | - write!( |
781 | | - f, |
782 | | - "{:02}:{:02}:{:02}.{:09}", |
783 | | - self.0.hour, self.0.minute, self.0.second, self.0.nanosecond |
784 | | - )?; |
785 | | - if self.0.time_zone == Self::UNSPECIFIED_TIMEZONE { |
786 | | - write!(f, ", Timezone=local")?; |
787 | | - } else { |
788 | | - write!(f, ", Timezone={}", self.0.time_zone)?; |
789 | | - } |
790 | | - write!(f, ", Daylight={:?}", self.0.daylight) |
791 | | - } |
792 | | -} |
793 | | - |
794 | | -impl Display for Time { |
795 | | - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
796 | | - write!(f, "{}", self.0) |
797 | | - } |
798 | | -} |
799 | | - |
800 | | -/// Error returned from failing to convert a byte slice into a [`Time`]. |
801 | | -#[derive(Clone, Copy, Debug, PartialEq, Eq)] |
802 | | -pub enum TimeByteConversionError { |
803 | | - /// One or more fields of the converted [`Time`] is invalid. |
804 | | - InvalidFields(TimeError), |
805 | | - /// The byte slice is not large enough to hold a [`Time`]. |
806 | | - InvalidSize, |
807 | | -} |
808 | | - |
809 | | -impl Display for TimeByteConversionError { |
810 | | - fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
811 | | - match self { |
812 | | - Self::InvalidFields(error) => write!(f, "{error}"), |
813 | | - Self::InvalidSize => write!( |
814 | | - f, |
815 | | - "the byte slice is not large enough to hold a Time struct" |
816 | | - ), |
817 | | - } |
818 | | - } |
819 | | -} |
820 | | - |
821 | | -impl TryFrom<&[u8]> for Time { |
822 | | - type Error = TimeByteConversionError; |
823 | | - |
824 | | - fn try_from(bytes: &[u8]) -> core::result::Result<Self, Self::Error> { |
825 | | - if size_of::<Self>() <= bytes.len() { |
826 | | - let year = u16::from_le_bytes(bytes[0..2].try_into().unwrap()); |
827 | | - let month = bytes[2]; |
828 | | - let day = bytes[3]; |
829 | | - let hour = bytes[4]; |
830 | | - let minute = bytes[5]; |
831 | | - let second = bytes[6]; |
832 | | - let nanosecond = u32::from_le_bytes(bytes[8..12].try_into().unwrap()); |
833 | | - let time_zone = match i16::from_le_bytes(bytes[12..14].try_into().unwrap()) { |
834 | | - Self::UNSPECIFIED_TIMEZONE => None, |
835 | | - num => Some(num), |
836 | | - }; |
837 | | - let daylight = Daylight::from_bits(bytes[14]).ok_or_else(|| { |
838 | | - TimeByteConversionError::InvalidFields(TimeError { |
839 | | - daylight: true, |
840 | | - ..Default::default() |
841 | | - }) |
842 | | - })?; |
843 | | - |
844 | | - let time_params = TimeParams { |
845 | | - year, |
846 | | - month, |
847 | | - day, |
848 | | - hour, |
849 | | - minute, |
850 | | - second, |
851 | | - nanosecond, |
852 | | - time_zone, |
853 | | - daylight, |
854 | | - }; |
855 | | - |
856 | | - Self::new(time_params).map_err(TimeByteConversionError::InvalidFields) |
857 | | - } else { |
858 | | - Err(TimeByteConversionError::InvalidSize) |
859 | | - } |
860 | | - } |
861 | | -} |
862 | | - |
863 | 558 | /// Unique key for a variable. |
864 | 559 | #[cfg(feature = "alloc")] |
865 | 560 | #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] |
|
0 commit comments