Skip to main content

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