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::atomic::{Atomic, AtomicBasicOps, AtomicType, Relaxed};
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}