xref: /linux/rust/kernel/debugfs/callback_adapters.rs (revision 644672e93a1aa6bfc3ebc102cbf9b8efad16e786)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2025 Google LLC.
3 
4 //! Adapters which allow the user to supply a write or read implementation as a value rather
5 //! than a trait implementation. If provided, it will override the trait implementation.
6 
7 use super::{
8     Reader,
9     Writer, //
10 };
11 
12 use crate::{
13     fmt,
14     prelude::*,
15     uaccess::UserSliceReader, //
16 };
17 
18 use core::{
19     marker::PhantomData,
20     ops::Deref, //
21 };
22 
23 /// # Safety
24 ///
25 /// To implement this trait, it must be safe to cast a `&Self` to a `&Inner`.
26 /// It is intended for use in unstacking adapters out of `FileOps` backings.
27 pub(crate) unsafe trait Adapter {
28     type Inner;
29 }
30 
31 /// Adapter to implement `Reader` via a callback with the same representation as `T`.
32 ///
33 /// * Layer it on top of `WriterAdapter` if you want to add a custom callback for `write`.
34 /// * Layer it on top of `NoWriter` to pass through any support present on the underlying type.
35 ///
36 /// # Invariants
37 ///
38 /// If an instance for `WritableAdapter<_, W>` is constructed, `W` is inhabited.
39 #[repr(transparent)]
40 pub(crate) struct WritableAdapter<D, W> {
41     inner: D,
42     _writer: PhantomData<W>,
43 }
44 
45 // SAFETY: Stripping off the adapter only removes constraints
46 unsafe impl<D, W> Adapter for WritableAdapter<D, W> {
47     type Inner = D;
48 }
49 
50 impl<D: Writer, W> Writer for WritableAdapter<D, W> {
51     fn write(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
52         self.inner.write(fmt)
53     }
54 }
55 
56 impl<D: Deref, W> Reader for WritableAdapter<D, W>
57 where
58     W: Fn(&D::Target, &mut UserSliceReader) -> Result + Send + Sync + 'static,
59 {
60     fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result {
61         // SAFETY: WritableAdapter<_, W> can only be constructed if W is inhabited
62         let w: &W = unsafe { materialize_zst() };
63         w(self.inner.deref(), reader)
64     }
65 }
66 
67 /// Adapter to implement `Writer` via a callback with the same representation as `T`.
68 ///
69 /// # Invariants
70 ///
71 /// If an instance for `FormatAdapter<_, F>` is constructed, `F` is inhabited.
72 #[repr(transparent)]
73 pub(crate) struct FormatAdapter<D, F> {
74     inner: D,
75     _formatter: PhantomData<F>,
76 }
77 
78 impl<D, F> Deref for FormatAdapter<D, F> {
79     type Target = D;
80     fn deref(&self) -> &D {
81         &self.inner
82     }
83 }
84 
85 impl<D, F> Writer for FormatAdapter<D, F>
86 where
87     F: Fn(&D, &mut fmt::Formatter<'_>) -> fmt::Result + 'static,
88 {
89     fn write(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
90         // SAFETY: FormatAdapter<_, F> can only be constructed if F is inhabited
91         let f: &F = unsafe { materialize_zst() };
92         f(&self.inner, fmt)
93     }
94 }
95 
96 // SAFETY: Stripping off the adapter only removes constraints
97 unsafe impl<D, F> Adapter for FormatAdapter<D, F> {
98     type Inner = D;
99 }
100 
101 #[repr(transparent)]
102 pub(crate) struct NoWriter<D> {
103     inner: D,
104 }
105 
106 // SAFETY: Stripping off the adapter only removes constraints
107 unsafe impl<D> Adapter for NoWriter<D> {
108     type Inner = D;
109 }
110 
111 impl<D> Deref for NoWriter<D> {
112     type Target = D;
113     fn deref(&self) -> &D {
114         &self.inner
115     }
116 }
117 
118 /// For types with a unique value, produce a static reference to it.
119 ///
120 /// # Safety
121 ///
122 /// The caller asserts that F is inhabited
123 unsafe fn materialize_zst<F>() -> &'static F {
124     const { assert!(core::mem::size_of::<F>() == 0) };
125     let zst_dangle: core::ptr::NonNull<F> = core::ptr::NonNull::dangling();
126     // SAFETY: While the pointer is dangling, it is a dangling pointer to a ZST, based on the
127     // assertion above. The type is also inhabited, by the caller's assertion. This means
128     // we can materialize it.
129     unsafe { zst_dangle.as_ref() }
130 }
131