xref: /linux/rust/kernel/debugfs/traits.rs (revision 59e6295fac26b8e85c1ea859cdd89fa1e47519d7)
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     uaccess::{
22         UserSliceReader,
23         UserSliceWriter, //
24     },
25 };
26 
27 use core::{
28     ops::{
29         Deref,
30         DerefMut, //
31     },
32     str::FromStr,
33 };
34 
35 use 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.
46 pub trait Writer {
47     /// Formats the value using the given formatter.
48     fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
49 }
50 
51 impl<T: Writer> Writer for Mutex<T> {
52     fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53         self.lock().write(f)
54     }
55 }
56 
57 impl<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.
64 pub 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`.
78 impl<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.
89 impl<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.
102 impl<T, A> BinaryWriter for Box<T, A>
103 where
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.
117 impl<T, A> BinaryWriter for Pin<Box<T, A>>
118 where
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.
132 impl<T> BinaryWriter for Arc<T>
133 where
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>`.
146 impl<T, A> BinaryWriter for Vec<T, A>
147 where
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`.
166 pub trait Reader {
167     /// Updates the value from the given user slice.
168     fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result;
169 }
170 
171 impl<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 
187 impl<T: AtomicType + FromStr> Reader for Atomic<T>
188 where
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.
209 pub 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`.
225 impl<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.
236 impl<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.
247 impl<T, A> BinaryReaderMut for Vec<T, A>
248 where
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.
264 pub 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`.
278 impl<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.
291 impl<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.
302 impl<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.
313 impl<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 }
322