kernel/debugfs/
traits.rs

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::Arc;
11use crate::sync::Mutex;
12use crate::transmute::{AsBytes, FromBytes};
13use crate::uaccess::{UserSliceReader, UserSliceWriter};
14use core::ops::{Deref, DerefMut};
15use core::str::FromStr;
16use 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.
30pub trait Writer {
31    /// Formats the value using the given formatter.
32    fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
33}
34
35impl<T: Writer> Writer for Mutex<T> {
36    fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        self.lock().write(f)
38    }
39}
40
41impl<T: fmt::Debug> Writer for T {
42    fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        writeln!(f, "{self:?}")
44    }
45}
46
47/// Trait for types that can be written out as binary.
48pub 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`.
62impl<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.
73impl<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.
86impl<T, A> BinaryWriter for Box<T, A>
87where
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.
101impl<T, A> BinaryWriter for Pin<Box<T, A>>
102where
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.
116impl<T> BinaryWriter for Arc<T>
117where
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>`.
130impl<T, A> BinaryWriter for Vec<T, A>
131where
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`.
157pub trait Reader {
158    /// Updates the value from the given user slice.
159    fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result;
160}
161
162impl<T: FromStr + Unpin> 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.
181pub 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`.
197impl<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.
208impl<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.
219impl<T, A> BinaryReaderMut for Vec<T, A>
220where
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.
246pub 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`.
260impl<T: BinaryReaderMut + Unpin> 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.
273impl<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.
284impl<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.
295impl<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
305macro_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
327impl_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);