File Index
Files and directories
Sign in
FILE

traits.rs

File preview with syntax highlighting.

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