From: Remo Senekowitsch Date: Wed, 11 Jun 2025 10:29:04 +0000 (+0200) Subject: rust: device: Introduce PropertyGuard X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=9bd791d9413b4b65e203c4ff84c8b8b2c8c3b770;p=users%2Fjedix%2Flinux-maple.git rust: device: Introduce PropertyGuard This abstraction is a way to force users to specify whether a property is supposed to be required or not. This allows us to move error logging of missing required properties into core, preventing a lot of boilerplate in drivers. It will be used by upcoming methods for reading device properties. Tested-by: Dirk Behme Signed-off-by: Remo Senekowitsch Link: https://lore.kernel.org/r/20250611102908.212514-6-remo@buenzli.dev [ Use prelude::* to avoid build failure; move PropertyGuard below Display impl of FwNode. - Danilo ] Signed-off-by: Danilo Krummrich --- diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs index 4cac335bad78c..2c94825789871 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -8,6 +8,7 @@ use core::ptr; use crate::{ bindings, + prelude::*, str::CStr, types::{ARef, Opaque}, }; @@ -154,3 +155,62 @@ impl core::fmt::Display for FwNode { Ok(()) } } + +/// A helper for reading device properties. +/// +/// Use [`Self::required_by`] if a missing property is considered a bug and +/// [`Self::optional`] otherwise. +/// +/// For convenience, [`Self::or`] and [`Self::or_default`] are provided. +pub struct PropertyGuard<'fwnode, 'name, T> { + /// The result of reading the property. + inner: Result, + /// The fwnode of the property, used for logging in the "required" case. + fwnode: &'fwnode FwNode, + /// The name of the property, used for logging in the "required" case. + name: &'name CStr, +} + +impl PropertyGuard<'_, '_, T> { + /// Access the property, indicating it is required. + /// + /// If the property is not present, the error is automatically logged. If a + /// missing property is not an error, use [`Self::optional`] instead. The + /// device is required to associate the log with it. + pub fn required_by(self, dev: &super::Device) -> Result { + if self.inner.is_err() { + dev_err!( + dev, + "{}: property '{}' is missing\n", + self.fwnode, + self.name + ); + } + self.inner + } + + /// Access the property, indicating it is optional. + /// + /// In contrast to [`Self::required_by`], no error message is logged if + /// the property is not present. + pub fn optional(self) -> Option { + self.inner.ok() + } + + /// Access the property or the specified default value. + /// + /// Do not pass a sentinel value as default to detect a missing property. + /// Use [`Self::required_by`] or [`Self::optional`] instead. + pub fn or(self, default: T) -> T { + self.inner.unwrap_or(default) + } +} + +impl PropertyGuard<'_, '_, T> { + /// Access the property or a default value. + /// + /// Use [`Self::or`] to specify a custom default value. + pub fn or_default(self) -> T { + self.inner.unwrap_or_default() + } +}