summaryrefslogtreecommitdiff
path: root/rust/kernel/debugfs/callback_adapters.rs
blob: 6c024230f676d55c8ddacb69de9c27587e29c636 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2025 Google LLC.

//! Adapters which allow the user to supply a write or read implementation as a value rather
//! than a trait implementation. If provided, it will override the trait implementation.

use super::{Reader, Writer};
use crate::prelude::*;
use crate::uaccess::UserSliceReader;
use core::fmt;
use core::fmt::Formatter;
use core::marker::PhantomData;
use core::ops::Deref;

/// # Safety
///
/// To implement this trait, it must be safe to cast a `&Self` to a `&Inner`.
/// It is intended for use in unstacking adapters out of `FileOps` backings.
pub(crate) unsafe trait Adapter {
    type Inner;
}

/// Adapter to implement `Reader` via a callback with the same representation as `T`.
///
/// * Layer it on top of `WriterAdapter` if you want to add a custom callback for `write`.
/// * Layer it on top of `NoWriter` to pass through any support present on the underlying type.
///
/// # Invariants
///
/// If an instance for `WritableAdapter<_, W>` is constructed, `W` is inhabited.
#[repr(transparent)]
pub(crate) struct WritableAdapter<D, W> {
    inner: D,
    _writer: PhantomData<W>,
}

// SAFETY: Stripping off the adapter only removes constraints
unsafe impl<D, W> Adapter for WritableAdapter<D, W> {
    type Inner = D;
}

impl<D: Writer, W> Writer for WritableAdapter<D, W> {
    fn write(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.inner.write(fmt)
    }
}

impl<D: Deref, W> Reader for WritableAdapter<D, W>
where
    W: Fn(&D::Target, &mut UserSliceReader) -> Result + Send + Sync + 'static,
{
    fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result {
        // SAFETY: WritableAdapter<_, W> can only be constructed if W is inhabited
        let w: &W = unsafe { materialize_zst() };
        w(self.inner.deref(), reader)
    }
}

/// Adapter to implement `Writer` via a callback with the same representation as `T`.
///
/// # Invariants
///
/// If an instance for `FormatAdapter<_, F>` is constructed, `F` is inhabited.
#[repr(transparent)]
pub(crate) struct FormatAdapter<D, F> {
    inner: D,
    _formatter: PhantomData<F>,
}

impl<D, F> Deref for FormatAdapter<D, F> {
    type Target = D;
    fn deref(&self) -> &D {
        &self.inner
    }
}

impl<D, F> Writer for FormatAdapter<D, F>
where
    F: Fn(&D, &mut Formatter<'_>) -> fmt::Result + 'static,
{
    fn write(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
        // SAFETY: FormatAdapter<_, F> can only be constructed if F is inhabited
        let f: &F = unsafe { materialize_zst() };
        f(&self.inner, fmt)
    }
}

// SAFETY: Stripping off the adapter only removes constraints
unsafe impl<D, F> Adapter for FormatAdapter<D, F> {
    type Inner = D;
}

#[repr(transparent)]
pub(crate) struct NoWriter<D> {
    inner: D,
}

// SAFETY: Stripping off the adapter only removes constraints
unsafe impl<D> Adapter for NoWriter<D> {
    type Inner = D;
}

impl<D> Deref for NoWriter<D> {
    type Target = D;
    fn deref(&self) -> &D {
        &self.inner
    }
}

/// For types with a unique value, produce a static reference to it.
///
/// # Safety
///
/// The caller asserts that F is inhabited
unsafe fn materialize_zst<F>() -> &'static F {
    const { assert!(core::mem::size_of::<F>() == 0) };
    let zst_dangle: core::ptr::NonNull<F> = core::ptr::NonNull::dangling();
    // SAFETY: While the pointer is dangling, it is a dangling pointer to a ZST, based on the
    // assertion above. The type is also inhabited, by the caller's assertion. This means
    // we can materialize it.
    unsafe { zst_dangle.as_ref() }
}