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