xref: /linux/rust/kernel/debugfs/traits.rs (revision eb3289fc474f74105e0627bf508e3f9742fd3b63)
15e40b591SMatthew Maurer // SPDX-License-Identifier: GPL-2.0
25e40b591SMatthew Maurer // Copyright (C) 2025 Google LLC.
35e40b591SMatthew Maurer 
45e40b591SMatthew Maurer //! Traits for rendering or updating values exported to DebugFS.
55e40b591SMatthew Maurer 
6*839dc1d1SMatthew Maurer use crate::prelude::*;
75e40b591SMatthew Maurer use crate::sync::Mutex;
8*839dc1d1SMatthew Maurer use crate::uaccess::UserSliceReader;
95e40b591SMatthew Maurer use core::fmt::{self, Debug, Formatter};
10*839dc1d1SMatthew Maurer use core::str::FromStr;
11*839dc1d1SMatthew Maurer use core::sync::atomic::{
12*839dc1d1SMatthew Maurer     AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64,
13*839dc1d1SMatthew Maurer     AtomicU8, AtomicUsize, Ordering,
14*839dc1d1SMatthew Maurer };
155e40b591SMatthew Maurer 
165e40b591SMatthew Maurer /// A trait for types that can be written into a string.
175e40b591SMatthew Maurer ///
185e40b591SMatthew Maurer /// This works very similarly to `Debug`, and is automatically implemented if `Debug` is
195e40b591SMatthew Maurer /// implemented for a type. It is also implemented for any writable type inside a `Mutex`.
205e40b591SMatthew Maurer ///
215e40b591SMatthew Maurer /// The derived implementation of `Debug` [may
225e40b591SMatthew Maurer /// change](https://doc.rust-lang.org/std/fmt/trait.Debug.html#stability)
235e40b591SMatthew Maurer /// between Rust versions, so if stability is key for your use case, please implement `Writer`
245e40b591SMatthew Maurer /// explicitly instead.
255e40b591SMatthew Maurer pub trait Writer {
265e40b591SMatthew Maurer     /// Formats the value using the given formatter.
275e40b591SMatthew Maurer     fn write(&self, f: &mut Formatter<'_>) -> fmt::Result;
285e40b591SMatthew Maurer }
295e40b591SMatthew Maurer 
305e40b591SMatthew Maurer impl<T: Writer> Writer for Mutex<T> {
315e40b591SMatthew Maurer     fn write(&self, f: &mut Formatter<'_>) -> fmt::Result {
325e40b591SMatthew Maurer         self.lock().write(f)
335e40b591SMatthew Maurer     }
345e40b591SMatthew Maurer }
355e40b591SMatthew Maurer 
365e40b591SMatthew Maurer impl<T: Debug> Writer for T {
375e40b591SMatthew Maurer     fn write(&self, f: &mut Formatter<'_>) -> fmt::Result {
385e40b591SMatthew Maurer         writeln!(f, "{self:?}")
395e40b591SMatthew Maurer     }
405e40b591SMatthew Maurer }
41*839dc1d1SMatthew Maurer 
42*839dc1d1SMatthew Maurer /// A trait for types that can be updated from a user slice.
43*839dc1d1SMatthew Maurer ///
44*839dc1d1SMatthew Maurer /// This works similarly to `FromStr`, but operates on a `UserSliceReader` rather than a &str.
45*839dc1d1SMatthew Maurer ///
46*839dc1d1SMatthew Maurer /// It is automatically implemented for all atomic integers, or any type that implements `FromStr`
47*839dc1d1SMatthew Maurer /// wrapped in a `Mutex`.
48*839dc1d1SMatthew Maurer pub trait Reader {
49*839dc1d1SMatthew Maurer     /// Updates the value from the given user slice.
50*839dc1d1SMatthew Maurer     fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result;
51*839dc1d1SMatthew Maurer }
52*839dc1d1SMatthew Maurer 
53*839dc1d1SMatthew Maurer impl<T: FromStr> Reader for Mutex<T> {
54*839dc1d1SMatthew Maurer     fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result {
55*839dc1d1SMatthew Maurer         let mut buf = [0u8; 128];
56*839dc1d1SMatthew Maurer         if reader.len() > buf.len() {
57*839dc1d1SMatthew Maurer             return Err(EINVAL);
58*839dc1d1SMatthew Maurer         }
59*839dc1d1SMatthew Maurer         let n = reader.len();
60*839dc1d1SMatthew Maurer         reader.read_slice(&mut buf[..n])?;
61*839dc1d1SMatthew Maurer 
62*839dc1d1SMatthew Maurer         let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?;
63*839dc1d1SMatthew Maurer         let val = s.trim().parse::<T>().map_err(|_| EINVAL)?;
64*839dc1d1SMatthew Maurer         *self.lock() = val;
65*839dc1d1SMatthew Maurer         Ok(())
66*839dc1d1SMatthew Maurer     }
67*839dc1d1SMatthew Maurer }
68*839dc1d1SMatthew Maurer 
69*839dc1d1SMatthew Maurer macro_rules! impl_reader_for_atomic {
70*839dc1d1SMatthew Maurer     ($(($atomic_type:ty, $int_type:ty)),*) => {
71*839dc1d1SMatthew Maurer         $(
72*839dc1d1SMatthew Maurer             impl Reader for $atomic_type {
73*839dc1d1SMatthew Maurer                 fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result {
74*839dc1d1SMatthew Maurer                     let mut buf = [0u8; 21]; // Enough for a 64-bit number.
75*839dc1d1SMatthew Maurer                     if reader.len() > buf.len() {
76*839dc1d1SMatthew Maurer                         return Err(EINVAL);
77*839dc1d1SMatthew Maurer                     }
78*839dc1d1SMatthew Maurer                     let n = reader.len();
79*839dc1d1SMatthew Maurer                     reader.read_slice(&mut buf[..n])?;
80*839dc1d1SMatthew Maurer 
81*839dc1d1SMatthew Maurer                     let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?;
82*839dc1d1SMatthew Maurer                     let val = s.trim().parse::<$int_type>().map_err(|_| EINVAL)?;
83*839dc1d1SMatthew Maurer                     self.store(val, Ordering::Relaxed);
84*839dc1d1SMatthew Maurer                     Ok(())
85*839dc1d1SMatthew Maurer                 }
86*839dc1d1SMatthew Maurer             }
87*839dc1d1SMatthew Maurer         )*
88*839dc1d1SMatthew Maurer     };
89*839dc1d1SMatthew Maurer }
90*839dc1d1SMatthew Maurer 
91*839dc1d1SMatthew Maurer impl_reader_for_atomic!(
92*839dc1d1SMatthew Maurer     (AtomicI16, i16),
93*839dc1d1SMatthew Maurer     (AtomicI32, i32),
94*839dc1d1SMatthew Maurer     (AtomicI64, i64),
95*839dc1d1SMatthew Maurer     (AtomicI8, i8),
96*839dc1d1SMatthew Maurer     (AtomicIsize, isize),
97*839dc1d1SMatthew Maurer     (AtomicU16, u16),
98*839dc1d1SMatthew Maurer     (AtomicU32, u32),
99*839dc1d1SMatthew Maurer     (AtomicU64, u64),
100*839dc1d1SMatthew Maurer     (AtomicU8, u8),
101*839dc1d1SMatthew Maurer     (AtomicUsize, usize)
102*839dc1d1SMatthew Maurer );
103