xref: /linux/rust/kernel/debugfs/traits.rs (revision b0319c4642638bad4b36974055b1c0894b2c7aa9)
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::alloc::Allocator;
7 use crate::fmt;
8 use crate::fs::file;
9 use crate::prelude::*;
10 use crate::sync::atomic::{Atomic, AtomicBasicOps, AtomicType, Relaxed};
11 use crate::sync::Arc;
12 use crate::sync::Mutex;
13 use crate::transmute::{AsBytes, FromBytes};
14 use crate::uaccess::{UserSliceReader, UserSliceWriter};
15 use core::ops::{Deref, DerefMut};
16 use 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.
27 pub trait Writer {
28     /// Formats the value using the given formatter.
29     fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
30 }
31 
32 impl<T: Writer> Writer for Mutex<T> {
33     fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34         self.lock().write(f)
35     }
36 }
37 
38 impl<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.
45 pub 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`.
59 impl<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.
70 impl<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.
83 impl<T, A> BinaryWriter for Box<T, A>
84 where
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.
98 impl<T, A> BinaryWriter for Pin<Box<T, A>>
99 where
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.
113 impl<T> BinaryWriter for Arc<T>
114 where
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>`.
127 impl<T, A> BinaryWriter for Vec<T, A>
128 where
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`.
154 pub trait Reader {
155     /// Updates the value from the given user slice.
156     fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result;
157 }
158 
159 impl<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 
175 impl<T: AtomicType + FromStr> Reader for Atomic<T>
176 where
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.
197 pub 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`.
213 impl<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.
224 impl<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.
235 impl<T, A> BinaryReaderMut for Vec<T, A>
236 where
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.
262 pub 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`.
276 impl<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.
289 impl<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.
300 impl<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.
311 impl<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 }
320