Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/kernel/debugfs/traits.rs
49000 views
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
321