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::atomic::{Atomic, AtomicBasicOps, AtomicType, Relaxed}; 8 use crate::sync::Mutex; 9 use crate::uaccess::UserSliceReader; 10 use core::fmt::{self, Debug, Formatter}; 11 use core::str::FromStr; 12 13 /// A trait for types that can be written into a string. 14 /// 15 /// This works very similarly to `Debug`, and is automatically implemented if `Debug` is 16 /// implemented for a type. It is also implemented for any writable type inside a `Mutex`. 17 /// 18 /// The derived implementation of `Debug` [may 19 /// change](https://doc.rust-lang.org/std/fmt/trait.Debug.html#stability) 20 /// between Rust versions, so if stability is key for your use case, please implement `Writer` 21 /// explicitly instead. 22 pub trait Writer { 23 /// Formats the value using the given formatter. 24 fn write(&self, f: &mut Formatter<'_>) -> fmt::Result; 25 } 26 27 impl<T: Writer> Writer for Mutex<T> { 28 fn write(&self, f: &mut Formatter<'_>) -> fmt::Result { 29 self.lock().write(f) 30 } 31 } 32 33 impl<T: Debug> Writer for T { 34 fn write(&self, f: &mut Formatter<'_>) -> fmt::Result { 35 writeln!(f, "{self:?}") 36 } 37 } 38 39 /// A trait for types that can be updated from a user slice. 40 /// 41 /// This works similarly to `FromStr`, but operates on a `UserSliceReader` rather than a &str. 42 /// 43 /// It is automatically implemented for all atomic integers, or any type that implements `FromStr` 44 /// wrapped in a `Mutex`. 45 pub trait Reader { 46 /// Updates the value from the given user slice. 47 fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result; 48 } 49 50 impl<T: FromStr + Unpin> Reader for Mutex<T> { 51 fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result { 52 let mut buf = [0u8; 128]; 53 if reader.len() > buf.len() { 54 return Err(EINVAL); 55 } 56 let n = reader.len(); 57 reader.read_slice(&mut buf[..n])?; 58 59 let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?; 60 let val = s.trim().parse::<T>().map_err(|_| EINVAL)?; 61 *self.lock() = val; 62 Ok(()) 63 } 64 } 65 66 impl<T: AtomicType + FromStr> Reader for Atomic<T> 67 where 68 T::Repr: AtomicBasicOps, 69 { 70 fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result { 71 let mut buf = [0u8; 21]; // Enough for a 64-bit number. 72 if reader.len() > buf.len() { 73 return Err(EINVAL); 74 } 75 let n = reader.len(); 76 reader.read_slice(&mut buf[..n])?; 77 78 let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?; 79 let val = s.trim().parse::<T>().map_err(|_| EINVAL)?; 80 self.store(val, Relaxed); 81 Ok(()) 82 } 83 } 84