libfdt: Make Phandle::new() const
Decouple the definition of valid phandle values enforced by
Phandle::new() from the FdtError type and allow callers to generate a
libfdt::Result<Phandle> by implementing the standard TryFrom trait.
This was initially intended to be used in const expressions e.g.
const PHANDLE: Phandle = Phandle::new().unwrap();
but this will actually required stabilization of const_option first. For
now, the constructor is at least marked const.
Test: atest liblibfdt.integration_test
Change-Id: Ib9893595b1dd3972782e488f087fec2872679293
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index d800c13..0a97141 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -505,12 +505,18 @@
pub struct Phandle(u32);
impl Phandle {
+ /// Minimum valid value for device tree phandles.
+ pub const MIN: Self = Self(1);
+ /// Maximum valid value for device tree phandles.
+ pub const MAX: Self = Self(libfdt_bindgen::FDT_MAX_PHANDLE);
+
/// Creates a new Phandle
- pub fn new(value: u32) -> Result<Self> {
- if value == 0 || value > libfdt_bindgen::FDT_MAX_PHANDLE {
- return Err(FdtError::BadPhandle);
+ pub const fn new(value: u32) -> Option<Self> {
+ if Self::MIN.0 <= value && value <= Self::MAX.0 {
+ Some(Self(value))
+ } else {
+ None
}
- Ok(Self(value))
}
}
@@ -520,6 +526,14 @@
}
}
+impl TryFrom<u32> for Phandle {
+ type Error = FdtError;
+
+ fn try_from(value: u32) -> Result<Self> {
+ Self::new(value).ok_or(FdtError::BadPhandle)
+ }
+}
+
/// Mutable FDT node.
pub struct FdtNodeMut<'a> {
fdt: &'a mut Fdt,
@@ -964,7 +978,7 @@
let ret = unsafe { libfdt_bindgen::fdt_find_max_phandle(self.as_ptr(), &mut phandle) };
fdt_err_expect_zero(ret)?;
- Phandle::new(phandle)
+ phandle.try_into()
}
/// Returns a node with the phandle
diff --git a/libs/libfdt/tests/api_test.rs b/libs/libfdt/tests/api_test.rs
index 61503eb..bd2b306 100644
--- a/libs/libfdt/tests/api_test.rs
+++ b/libs/libfdt/tests/api_test.rs
@@ -142,10 +142,30 @@
#[test]
fn phandle_new() {
- let phandle_u32 = 0x55;
- let phandle = Phandle::new(phandle_u32).unwrap();
+ let valid_phandles = [
+ u32::from(Phandle::MIN),
+ u32::from(Phandle::MIN).checked_add(1).unwrap(),
+ 0x55,
+ u32::from(Phandle::MAX).checked_sub(1).unwrap(),
+ u32::from(Phandle::MAX),
+ ];
- assert_eq!(u32::from(phandle), phandle_u32);
+ for value in valid_phandles {
+ let phandle = Phandle::new(value).unwrap();
+
+ assert_eq!(value.try_into(), Ok(phandle));
+ assert_eq!(u32::from(phandle), value);
+ }
+
+ let bad_phandles = [
+ u32::from(Phandle::MIN).checked_sub(1).unwrap(),
+ u32::from(Phandle::MAX).checked_add(1).unwrap(),
+ ];
+
+ for value in bad_phandles {
+ assert_eq!(Phandle::new(value), None);
+ assert_eq!(Phandle::try_from(value), Err(FdtError::BadPhandle));
+ }
}
#[test]