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