1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) 2025 Google LLC. 3 4 //! Traits for rendering or updating values exported to DebugFS. 5 6 use crate::prelude::*; 7 use crate::sync::Mutex; 8 use crate::uaccess::UserSliceReader; 9 use core::fmt::{self, Debug, Formatter}; 10 use core::str::FromStr; 11 use core::sync::atomic::{ 12 AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64, 13 AtomicU8, AtomicUsize, Ordering, 14 }; 15 16 /// A trait for types that can be written into a string. 17 /// 18 /// This works very similarly to `Debug`, and is automatically implemented if `Debug` is 19 /// implemented for a type. It is also implemented for any writable type inside a `Mutex`. 20 /// 21 /// The derived implementation of `Debug` [may 22 /// change](https://doc.rust-lang.org/std/fmt/trait.Debug.html#stability) 23 /// between Rust versions, so if stability is key for your use case, please implement `Writer` 24 /// explicitly instead. 25 pub trait Writer { 26 /// Formats the value using the given formatter. 27 fn write(&self, f: &mut Formatter<'_>) -> fmt::Result; 28 } 29 30 impl<T: Writer> Writer for Mutex<T> { 31 fn write(&self, f: &mut Formatter<'_>) -> fmt::Result { 32 self.lock().write(f) 33 } 34 } 35 36 impl<T: Debug> Writer for T { 37 fn write(&self, f: &mut Formatter<'_>) -> fmt::Result { 38 writeln!(f, "{self:?}") 39 } 40 } 41 42 /// A trait for types that can be updated from a user slice. 43 /// 44 /// This works similarly to `FromStr`, but operates on a `UserSliceReader` rather than a &str. 45 /// 46 /// It is automatically implemented for all atomic integers, or any type that implements `FromStr` 47 /// wrapped in a `Mutex`. 48 pub trait Reader { 49 /// Updates the value from the given user slice. 50 fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result; 51 } 52 53 impl<T: FromStr> Reader for Mutex<T> { 54 fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result { 55 let mut buf = [0u8; 128]; 56 if reader.len() > buf.len() { 57 return Err(EINVAL); 58 } 59 let n = reader.len(); 60 reader.read_slice(&mut buf[..n])?; 61 62 let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?; 63 let val = s.trim().parse::<T>().map_err(|_| EINVAL)?; 64 *self.lock() = val; 65 Ok(()) 66 } 67 } 68 69 macro_rules! impl_reader_for_atomic { 70 ($(($atomic_type:ty, $int_type:ty)),*) => { 71 $( 72 impl Reader for $atomic_type { 73 fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result { 74 let mut buf = [0u8; 21]; // Enough for a 64-bit number. 75 if reader.len() > buf.len() { 76 return Err(EINVAL); 77 } 78 let n = reader.len(); 79 reader.read_slice(&mut buf[..n])?; 80 81 let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?; 82 let val = s.trim().parse::<$int_type>().map_err(|_| EINVAL)?; 83 self.store(val, Ordering::Relaxed); 84 Ok(()) 85 } 86 } 87 )* 88 }; 89 } 90 91 impl_reader_for_atomic!( 92 (AtomicI16, i16), 93 (AtomicI32, i32), 94 (AtomicI64, i64), 95 (AtomicI8, i8), 96 (AtomicIsize, isize), 97 (AtomicU16, u16), 98 (AtomicU32, u32), 99 (AtomicU64, u64), 100 (AtomicU8, u8), 101 (AtomicUsize, usize) 102 ); 103