1 use core::fmt;
2 
3 /// A revision of the UEFI specification.
4 ///
5 /// The major revision number is incremented on major, API-incompatible changes.
6 ///
7 /// The minor revision number is incremented on minor changes,
8 /// it is stored as a two-digit binary-coded decimal.
9 ///
10 /// # Display format
11 ///
12 /// For major revision 2 and later, if the lower minor digit is zero,
13 /// the revision is formatted as "major.minor-upper". Otherwise it's
14 /// formatted as "major.minor-upper.minor-lower". This format is
15 /// described in the "EFI System Table" section of the UEFI
16 /// Specification.
17 ///
18 /// Prior to major version 2, the revision is always formatted as
19 /// "major.minor", with minor left-padded with zero if minor-upper is
20 /// zero.
21 ///
22 /// Examples:
23 ///
24 /// ```
25 /// # use uefi_raw::table::Revision;
26 /// assert_eq!(Revision::EFI_1_02.to_string(), "1.02");
27 /// assert_eq!(Revision::EFI_1_10.to_string(), "1.10");
28 /// assert_eq!(Revision::EFI_2_00.to_string(), "2.0");
29 /// assert_eq!(Revision::EFI_2_30.to_string(), "2.3");
30 /// assert_eq!(Revision::EFI_2_31.to_string(), "2.3.1");
31 /// assert_eq!(Revision::EFI_2_100.to_string(), "2.10");
32 /// ```
33 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
34 #[repr(transparent)]
35 pub struct Revision(pub u32);
36 
37 // Allow missing docs, there's nothing useful to document about these
38 // constants.
39 #[allow(missing_docs)]
40 impl Revision {
41     pub const EFI_1_02: Self = Self::new(1, 2);
42     pub const EFI_1_10: Self = Self::new(1, 10);
43     pub const EFI_2_00: Self = Self::new(2, 00);
44     pub const EFI_2_10: Self = Self::new(2, 10);
45     pub const EFI_2_20: Self = Self::new(2, 20);
46     pub const EFI_2_30: Self = Self::new(2, 30);
47     pub const EFI_2_31: Self = Self::new(2, 31);
48     pub const EFI_2_40: Self = Self::new(2, 40);
49     pub const EFI_2_50: Self = Self::new(2, 50);
50     pub const EFI_2_60: Self = Self::new(2, 60);
51     pub const EFI_2_70: Self = Self::new(2, 70);
52     pub const EFI_2_80: Self = Self::new(2, 80);
53     pub const EFI_2_90: Self = Self::new(2, 90);
54     pub const EFI_2_100: Self = Self::new(2, 100);
55 }
56 
57 impl Revision {
58     /// Creates a new revision.
59     #[must_use]
new(major: u16, minor: u16) -> Self60     pub const fn new(major: u16, minor: u16) -> Self {
61         let major = major as u32;
62         let minor = minor as u32;
63         let value = (major << 16) | minor;
64         Self(value)
65     }
66 
67     /// Returns the major revision.
68     #[must_use]
major(self) -> u1669     pub const fn major(self) -> u16 {
70         (self.0 >> 16) as u16
71     }
72 
73     /// Returns the minor revision.
74     #[must_use]
minor(self) -> u1675     pub const fn minor(self) -> u16 {
76         self.0 as u16
77     }
78 }
79 
80 impl fmt::Display for Revision {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result81     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82         let (major, minor) = (self.major(), self.minor());
83 
84         if major < 2 {
85             write!(f, "{major}.{minor:02}")
86         } else {
87             let (minor, patch) = (minor / 10, minor % 10);
88             if patch == 0 {
89                 write!(f, "{major}.{minor}")
90             } else {
91                 write!(f, "{major}.{minor}.{patch}")
92             }
93         }
94     }
95 }
96 
97 #[cfg(test)]
98 mod tests {
99     use super::*;
100 
101     #[test]
test_revision()102     fn test_revision() {
103         let rev = Revision::EFI_2_31;
104         assert_eq!(rev.major(), 2);
105         assert_eq!(rev.minor(), 31);
106         assert_eq!(rev.0, 0x0002_001f);
107 
108         assert!(Revision::EFI_1_10 < Revision::EFI_2_00);
109     }
110 }
111