1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//! Module for the [`BootPolicy`] helper type.

use core::fmt::{Display, Formatter};

/// Errors that can happen when working with [`BootPolicy`].
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq, Ord)]
pub enum BootPolicyError {
    /// Only `0` and `1` are valid integers, all other values are undefined.
    InvalidInteger(u8),
}

impl Display for BootPolicyError {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        let s = match self {
            Self::InvalidInteger(_) => {
                "Only `0` and `1` are valid integers, all other values are undefined."
            }
        };
        f.write_str(s)
    }
}

#[cfg(feature = "unstable")]
impl core::error::Error for BootPolicyError {}

/// The UEFI boot policy is a property that influences the behaviour of
/// various UEFI functions that load files (typically UEFI images).
///
/// This type is not ABI compatible. On the ABI level, this is an UEFI
/// boolean.
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
pub enum BootPolicy {
    /// Indicates that the request originates from the boot manager, and that
    /// the boot manager is attempting to load the provided `file_path` as a
    /// boot selection.
    ///
    /// Boot selection refers to what a user has chosen in the (GUI) boot menu.
    ///
    /// This corresponds to the `TRUE` value in the UEFI spec.
    BootSelection,
    /// The provided `file_path` must match an exact file to be loaded.
    ///
    /// This corresponds to the `FALSE` value in the UEFI spec.
    #[default]
    ExactMatch,
}

impl From<BootPolicy> for bool {
    fn from(value: BootPolicy) -> Self {
        match value {
            BootPolicy::BootSelection => true,
            BootPolicy::ExactMatch => false,
        }
    }
}

impl From<bool> for BootPolicy {
    fn from(value: bool) -> Self {
        match value {
            true => Self::BootSelection,
            false => Self::ExactMatch,
        }
    }
}

impl From<BootPolicy> for u8 {
    fn from(value: BootPolicy) -> Self {
        match value {
            BootPolicy::BootSelection => 1,
            BootPolicy::ExactMatch => 0,
        }
    }
}

impl TryFrom<u8> for BootPolicy {
    type Error = BootPolicyError;
    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(Self::ExactMatch),
            1 => Ok(Self::BootSelection),
            err => Err(Self::Error::InvalidInteger(err)),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn boot_policy() {
        assert_eq!(bool::from(BootPolicy::ExactMatch), false);
        assert_eq!(bool::from(BootPolicy::BootSelection), true);

        assert_eq!(BootPolicy::from(false), BootPolicy::ExactMatch);
        assert_eq!(BootPolicy::from(true), BootPolicy::BootSelection);

        assert_eq!(u8::from(BootPolicy::ExactMatch), 0);
        assert_eq!(u8::from(BootPolicy::BootSelection), 1);

        assert_eq!(BootPolicy::try_from(0), Ok(BootPolicy::ExactMatch));
        assert_eq!(BootPolicy::try_from(1), Ok(BootPolicy::BootSelection));
        assert_eq!(
            BootPolicy::try_from(2),
            Err(BootPolicyError::InvalidInteger(2))
        );
    }
}