projects/linux·blob uaccess-cleanups · refs

321 lines · 8.9 KiB

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}