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::alloc::Allocator; 7 use crate::fs::file; 8 use crate::prelude::*; 9 use crate::sync::Arc; 10 use crate::sync::Mutex; 11 use crate::transmute::{AsBytes, FromBytes}; 12 use crate::uaccess::{UserSliceReader, UserSliceWriter}; 13 use core::fmt::{self, Debug, Formatter}; 14 use core::ops::{Deref, DerefMut}; 15 use core::str::FromStr; 16 use core::sync::atomic::{ 17 AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64, 18 AtomicU8, AtomicUsize, Ordering, 19 }; 20 21 /// A trait for types that can be written into a string. 22 /// 23 /// This works very similarly to `Debug`, and is automatically implemented if `Debug` is 24 /// implemented for a type. It is also implemented for any writable type inside a `Mutex`. 25 /// 26 /// The derived implementation of `Debug` [may 27 /// change](https://doc.rust-lang.org/std/fmt/trait.Debug.html#stability) 28 /// between Rust versions, so if stability is key for your use case, please implement `Writer` 29 /// explicitly instead. 30 pub trait Writer { 31 /// Formats the value using the given formatter. 32 fn write(&self, f: &mut Formatter<'_>) -> fmt::Result; 33 } 34 35 impl<T: Writer> Writer for Mutex<T> { 36 fn write(&self, f: &mut Formatter<'_>) -> fmt::Result { 37 self.lock().write(f) 38 } 39 } 40 41 impl<T: Debug> Writer for T { 42 fn write(&self, f: &mut Formatter<'_>) -> fmt::Result { 43 writeln!(f, "{self:?}") 44 } 45 } 46 47 /// Trait for types that can be written out as binary. 48 pub trait BinaryWriter { 49 /// Writes the binary form of `self` into `writer`. 50 /// 51 /// `offset` is the requested offset into the binary representation of `self`. 52 /// 53 /// On success, returns the number of bytes written in to `writer`. 54 fn write_to_slice( 55 &self, 56 writer: &mut UserSliceWriter, 57 offset: &mut file::Offset, 58 ) -> Result<usize>; 59 } 60 61 // Base implementation for any `T: AsBytes`. 62 impl<T: AsBytes> BinaryWriter for T { 63 fn write_to_slice( 64 &self, 65 writer: &mut UserSliceWriter, 66 offset: &mut file::Offset, 67 ) -> Result<usize> { 68 writer.write_slice_file(self.as_bytes(), offset) 69 } 70 } 71 72 // Delegate for `Mutex<T>`: Support a `T` with an outer mutex. 73 impl<T: BinaryWriter> BinaryWriter for Mutex<T> { 74 fn write_to_slice( 75 &self, 76 writer: &mut UserSliceWriter, 77 offset: &mut file::Offset, 78 ) -> Result<usize> { 79 let guard = self.lock(); 80 81 guard.write_to_slice(writer, offset) 82 } 83 } 84 85 // Delegate for `Box<T, A>`: Support a `Box<T, A>` with no lock or an inner lock. 86 impl<T, A> BinaryWriter for Box<T, A> 87 where 88 T: BinaryWriter, 89 A: Allocator, 90 { 91 fn write_to_slice( 92 &self, 93 writer: &mut UserSliceWriter, 94 offset: &mut file::Offset, 95 ) -> Result<usize> { 96 self.deref().write_to_slice(writer, offset) 97 } 98 } 99 100 // Delegate for `Pin<Box<T, A>>`: Support a `Pin<Box<T, A>>` with no lock or an inner lock. 101 impl<T, A> BinaryWriter for Pin<Box<T, A>> 102 where 103 T: BinaryWriter, 104 A: Allocator, 105 { 106 fn write_to_slice( 107 &self, 108 writer: &mut UserSliceWriter, 109 offset: &mut file::Offset, 110 ) -> Result<usize> { 111 self.deref().write_to_slice(writer, offset) 112 } 113 } 114 115 // Delegate for `Arc<T>`: Support a `Arc<T>` with no lock or an inner lock. 116 impl<T> BinaryWriter for Arc<T> 117 where 118 T: BinaryWriter, 119 { 120 fn write_to_slice( 121 &self, 122 writer: &mut UserSliceWriter, 123 offset: &mut file::Offset, 124 ) -> Result<usize> { 125 self.deref().write_to_slice(writer, offset) 126 } 127 } 128 129 // Delegate for `Vec<T, A>`. 130 impl<T, A> BinaryWriter for Vec<T, A> 131 where 132 T: AsBytes, 133 A: Allocator, 134 { 135 fn write_to_slice( 136 &self, 137 writer: &mut UserSliceWriter, 138 offset: &mut file::Offset, 139 ) -> Result<usize> { 140 let slice = self.as_slice(); 141 142 // SAFETY: `T: AsBytes` allows us to treat `&[T]` as `&[u8]`. 143 let buffer = unsafe { 144 core::slice::from_raw_parts(slice.as_ptr().cast(), core::mem::size_of_val(slice)) 145 }; 146 147 writer.write_slice_file(buffer, offset) 148 } 149 } 150 151 /// A trait for types that can be updated from a user slice. 152 /// 153 /// This works similarly to `FromStr`, but operates on a `UserSliceReader` rather than a &str. 154 /// 155 /// It is automatically implemented for all atomic integers, or any type that implements `FromStr` 156 /// wrapped in a `Mutex`. 157 pub trait Reader { 158 /// Updates the value from the given user slice. 159 fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result; 160 } 161 162 impl<T: FromStr> Reader for Mutex<T> { 163 fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result { 164 let mut buf = [0u8; 128]; 165 if reader.len() > buf.len() { 166 return Err(EINVAL); 167 } 168 let n = reader.len(); 169 reader.read_slice(&mut buf[..n])?; 170 171 let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?; 172 let val = s.trim().parse::<T>().map_err(|_| EINVAL)?; 173 *self.lock() = val; 174 Ok(()) 175 } 176 } 177 178 /// Trait for types that can be constructed from a binary representation. 179 /// 180 /// See also [`BinaryReader`] for interior mutability. 181 pub trait BinaryReaderMut { 182 /// Reads the binary form of `self` from `reader`. 183 /// 184 /// Same as [`BinaryReader::read_from_slice`], but takes a mutable reference. 185 /// 186 /// `offset` is the requested offset into the binary representation of `self`. 187 /// 188 /// On success, returns the number of bytes read from `reader`. 189 fn read_from_slice_mut( 190 &mut self, 191 reader: &mut UserSliceReader, 192 offset: &mut file::Offset, 193 ) -> Result<usize>; 194 } 195 196 // Base implementation for any `T: AsBytes + FromBytes`. 197 impl<T: AsBytes + FromBytes> BinaryReaderMut for T { 198 fn read_from_slice_mut( 199 &mut self, 200 reader: &mut UserSliceReader, 201 offset: &mut file::Offset, 202 ) -> Result<usize> { 203 reader.read_slice_file(self.as_bytes_mut(), offset) 204 } 205 } 206 207 // Delegate for `Box<T, A>`: Support a `Box<T, A>` with an outer lock. 208 impl<T: ?Sized + BinaryReaderMut, A: Allocator> BinaryReaderMut for Box<T, A> { 209 fn read_from_slice_mut( 210 &mut self, 211 reader: &mut UserSliceReader, 212 offset: &mut file::Offset, 213 ) -> Result<usize> { 214 self.deref_mut().read_from_slice_mut(reader, offset) 215 } 216 } 217 218 // Delegate for `Vec<T, A>`: Support a `Vec<T, A>` with an outer lock. 219 impl<T, A> BinaryReaderMut for Vec<T, A> 220 where 221 T: AsBytes + FromBytes, 222 A: Allocator, 223 { 224 fn read_from_slice_mut( 225 &mut self, 226 reader: &mut UserSliceReader, 227 offset: &mut file::Offset, 228 ) -> Result<usize> { 229 let slice = self.as_mut_slice(); 230 231 // SAFETY: `T: AsBytes + FromBytes` allows us to treat `&mut [T]` as `&mut [u8]`. 232 let buffer = unsafe { 233 core::slice::from_raw_parts_mut( 234 slice.as_mut_ptr().cast(), 235 core::mem::size_of_val(slice), 236 ) 237 }; 238 239 reader.read_slice_file(buffer, offset) 240 } 241 } 242 243 /// Trait for types that can be constructed from a binary representation. 244 /// 245 /// See also [`BinaryReaderMut`] for the mutable version. 246 pub trait BinaryReader { 247 /// Reads the binary form of `self` from `reader`. 248 /// 249 /// `offset` is the requested offset into the binary representation of `self`. 250 /// 251 /// On success, returns the number of bytes read from `reader`. 252 fn read_from_slice( 253 &self, 254 reader: &mut UserSliceReader, 255 offset: &mut file::Offset, 256 ) -> Result<usize>; 257 } 258 259 // Delegate for `Mutex<T>`: Support a `T` with an outer `Mutex`. 260 impl<T: BinaryReaderMut> BinaryReader for Mutex<T> { 261 fn read_from_slice( 262 &self, 263 reader: &mut UserSliceReader, 264 offset: &mut file::Offset, 265 ) -> Result<usize> { 266 let mut this = self.lock(); 267 268 this.read_from_slice_mut(reader, offset) 269 } 270 } 271 272 // Delegate for `Box<T, A>`: Support a `Box<T, A>` with an inner lock. 273 impl<T: ?Sized + BinaryReader, A: Allocator> BinaryReader for Box<T, A> { 274 fn read_from_slice( 275 &self, 276 reader: &mut UserSliceReader, 277 offset: &mut file::Offset, 278 ) -> Result<usize> { 279 self.deref().read_from_slice(reader, offset) 280 } 281 } 282 283 // Delegate for `Pin<Box<T, A>>`: Support a `Pin<Box<T, A>>` with an inner lock. 284 impl<T: ?Sized + BinaryReader, A: Allocator> BinaryReader for Pin<Box<T, A>> { 285 fn read_from_slice( 286 &self, 287 reader: &mut UserSliceReader, 288 offset: &mut file::Offset, 289 ) -> Result<usize> { 290 self.deref().read_from_slice(reader, offset) 291 } 292 } 293 294 // Delegate for `Arc<T>`: Support an `Arc<T>` with an inner lock. 295 impl<T: ?Sized + BinaryReader> BinaryReader for Arc<T> { 296 fn read_from_slice( 297 &self, 298 reader: &mut UserSliceReader, 299 offset: &mut file::Offset, 300 ) -> Result<usize> { 301 self.deref().read_from_slice(reader, offset) 302 } 303 } 304 305 macro_rules! impl_reader_for_atomic { 306 ($(($atomic_type:ty, $int_type:ty)),*) => { 307 $( 308 impl Reader for $atomic_type { 309 fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result { 310 let mut buf = [0u8; 21]; // Enough for a 64-bit number. 311 if reader.len() > buf.len() { 312 return Err(EINVAL); 313 } 314 let n = reader.len(); 315 reader.read_slice(&mut buf[..n])?; 316 317 let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?; 318 let val = s.trim().parse::<$int_type>().map_err(|_| EINVAL)?; 319 self.store(val, Ordering::Relaxed); 320 Ok(()) 321 } 322 } 323 )* 324 }; 325 } 326 327 impl_reader_for_atomic!( 328 (AtomicI16, i16), 329 (AtomicI32, i32), 330 (AtomicI64, i64), 331 (AtomicI8, i8), 332 (AtomicIsize, isize), 333 (AtomicU16, u16), 334 (AtomicU32, u32), 335 (AtomicU64, u64), 336 (AtomicU8, u8), 337 (AtomicUsize, usize) 338 ); 339