summaryrefslogtreecommitdiff
path: root/rust/kernel/fmt.rs
diff options
context:
space:
mode:
authorTamir Duberstein <tamird@gmail.com>2025-10-18 15:16:36 -0400
committerMiguel Ojeda <ojeda@kernel.org>2025-10-22 07:15:31 +0200
commitc5cf01ba8dfe9c0f631ace6f64ec436303783000 (patch)
tree39db5b3b956b1ca76dbc940162ff84c9a88388c1 /rust/kernel/fmt.rs
parent1dcd763ba1f62c1305a03bc7d5bd1d44c20a4f5e (diff)
rust: support formatting of foreign types
Introduce a `fmt!` macro which wraps all arguments in `kernel::fmt::Adapter` and a `kernel::fmt::Display` trait. This enables formatting of foreign types (like `core::ffi::CStr`) that do not implement `core::fmt::Display` due to concerns around lossy conversions which do not apply in the kernel. Suggested-by: Alice Ryhl <aliceryhl@google.com> Link: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/Custom.20formatting/with/516476467 Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Acked-by: Danilo Krummrich <dakr@kernel.org> Reviewed-by: Benno Lossin <lossin@kernel.org> Signed-off-by: Tamir Duberstein <tamird@gmail.com> Link: https://patch.msgid.link/20251018-cstr-core-v18-15-9378a54385f8@gmail.com Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Diffstat (limited to 'rust/kernel/fmt.rs')
-rw-r--r--rust/kernel/fmt.rs87
1 files changed, 86 insertions, 1 deletions
diff --git a/rust/kernel/fmt.rs b/rust/kernel/fmt.rs
index 0306e8388968..84d634201d90 100644
--- a/rust/kernel/fmt.rs
+++ b/rust/kernel/fmt.rs
@@ -4,4 +4,89 @@
//!
//! This module is intended to be used in place of `core::fmt` in kernel code.
-pub use core::fmt::{Arguments, Debug, Display, Error, Formatter, Result, Write};
+pub use core::fmt::{Arguments, Debug, Error, Formatter, Result, Write};
+
+/// Internal adapter used to route allow implementations of formatting traits for foreign types.
+///
+/// It is inserted automatically by the [`fmt!`] macro and is not meant to be used directly.
+///
+/// [`fmt!`]: crate::prelude::fmt!
+#[doc(hidden)]
+pub struct Adapter<T>(pub T);
+
+macro_rules! impl_fmt_adapter_forward {
+ ($($trait:ident),* $(,)?) => {
+ $(
+ impl<T: $trait> $trait for Adapter<T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let Self(t) = self;
+ $trait::fmt(t, f)
+ }
+ }
+ )*
+ };
+}
+
+use core::fmt::{Binary, LowerExp, LowerHex, Octal, Pointer, UpperExp, UpperHex};
+impl_fmt_adapter_forward!(Debug, LowerHex, UpperHex, Octal, Binary, Pointer, LowerExp, UpperExp);
+
+/// A copy of [`core::fmt::Display`] that allows us to implement it for foreign types.
+///
+/// Types should implement this trait rather than [`core::fmt::Display`]. Together with the
+/// [`Adapter`] type and [`fmt!`] macro, it allows for formatting foreign types (e.g. types from
+/// core) which do not implement [`core::fmt::Display`] directly.
+///
+/// [`fmt!`]: crate::prelude::fmt!
+pub trait Display {
+ /// Same as [`core::fmt::Display::fmt`].
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result;
+}
+
+impl<T: ?Sized + Display> Display for &T {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ Display::fmt(*self, f)
+ }
+}
+
+impl<T: ?Sized + Display> core::fmt::Display for Adapter<&T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let Self(t) = self;
+ Display::fmt(t, f)
+ }
+}
+
+macro_rules! impl_display_forward {
+ ($(
+ $( { $($generics:tt)* } )? $ty:ty $( { where $($where:tt)* } )?
+ ),* $(,)?) => {
+ $(
+ impl$($($generics)*)? Display for $ty $(where $($where)*)? {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ core::fmt::Display::fmt(self, f)
+ }
+ }
+ )*
+ };
+}
+
+impl_display_forward!(
+ bool,
+ char,
+ core::panic::PanicInfo<'_>,
+ Arguments<'_>,
+ i128,
+ i16,
+ i32,
+ i64,
+ i8,
+ isize,
+ str,
+ u128,
+ u16,
+ u32,
+ u64,
+ u8,
+ usize,
+ {<T: ?Sized>} crate::sync::Arc<T> {where crate::sync::Arc<T>: core::fmt::Display},
+ {<T: ?Sized>} crate::sync::UniqueArc<T> {where crate::sync::UniqueArc<T>: core::fmt::Display},
+);