aboutsummaryrefslogtreecommitdiffstats
path: root/rust/kernel/types/for_lt.rs
blob: b8f422c802dcabc5bec151ce325d27f8ec89c104 (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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// SPDX-License-Identifier: Apache-2.0 OR MIT

//! Provide implementation and test of the [`trait@ForLt`] and [`trait@CovariantForLt`] traits and
//! macros.
//!
//! This module is hidden and users should just use [`ForLt!`](macro@ForLt) /
//! [`CovariantForLt!`](macro@CovariantForLt) directly.

use core::marker::PhantomData;

/// Representation of types generic over a lifetime.
///
/// # Macro
///
/// It is not recommended to implement this trait directly. [`ForLt!`](macro@ForLt) macro is
/// provided to obtain a type that implements this trait.
///
/// The full syntax is
///
/// ```
/// # use kernel::types::ForLt;
/// # fn expect_lt<F: ForLt>() {}
/// # struct TypeThatUse<'a>(&'a ());
/// # expect_lt::<
/// ForLt!(for<'a> TypeThatUse<'a>)
/// # >();
/// ```
///
/// which gives a type so that `<ForLt!(for<'a> TypeThatUse<'a>) as ForLt>::Of<'b>`
/// is `TypeThatUse<'b>`.
///
/// You may also use a short-hand syntax which works similar to lifetime elision.
/// The macro also accepts types that do not involve a lifetime at all.
///
/// ```
/// # use kernel::types::ForLt;
/// # fn expect_lt<F: ForLt>() {}
/// # struct TypeThatUse<'a>(&'a ());
/// # expect_lt::<
/// ForLt!(TypeThatUse<'_>) // Equivalent to `ForLt!(for<'a> TypeThatUse<'a>)`.
/// # >();
/// # expect_lt::<
/// ForLt!(&u32) // Equivalent to `ForLt!(for<'a> &'a u32)`.
/// # >();
/// # expect_lt::<
/// ForLt!(u32) // Equivalent to `ForLt!(for<'a> u32)`.
/// # >();
/// ```
pub trait ForLt {
    /// The type parameterized by the lifetime.
    type Of<'a>: 'a;
}
pub use macros::ForLt;

/// [`trait@ForLt`] subtrait for types that are covariant over their lifetime parameter.
///
/// Provides a safe [`cast_ref`](CovariantForLt::cast_ref) method for types that are proven to be
/// covariant. The `CovariantForLt!` macro syntax is the same as `ForLt!`.
///
/// # Macro
///
/// It is not recommended to implement this trait directly.
/// [`CovariantForLt!`](macro@CovariantForLt) macro is provided to obtain a type that implements
/// this trait.
///
/// The full syntax is
///
/// ```
/// # use kernel::types::CovariantForLt;
/// # fn expect_lt<F: CovariantForLt>() {}
/// # struct TypeThatUse<'a>(&'a ());
/// # expect_lt::<
/// CovariantForLt!(for<'a> TypeThatUse<'a>)
/// # >();
/// ```
///
/// which gives a type so that
/// `<CovariantForLt!(for<'a> TypeThatUse<'a>) as CovariantForLt>::Of<'b>`
/// is `TypeThatUse<'b>`.
///
/// You may also use a short-hand syntax which works similar to lifetime elision.
/// The macro also accepts types that do not involve a lifetime at all.
///
/// ```
/// # use kernel::types::CovariantForLt;
/// # fn expect_lt<F: CovariantForLt>() {}
/// # struct TypeThatUse<'a>(&'a ());
/// # expect_lt::<
/// CovariantForLt!(TypeThatUse<'_>) // Equivalent to `CovariantForLt!(for<'a> TypeThatUse<'a>)`.
/// # >();
/// # expect_lt::<
/// CovariantForLt!(&u32) // Equivalent to `CovariantForLt!(for<'a> &'a u32)`.
/// # >();
/// # expect_lt::<
/// CovariantForLt!(u32) // Equivalent to `CovariantForLt!(for<'a> u32)`.
/// # >();
/// ```
///
/// The macro will attempt to prove that the type is indeed covariant over the lifetime supplied.
/// When it cannot be syntactically proven, it will emit checks to ask the Rust compiler to prove
/// it.
///
/// ```ignore,compile_fail
/// # use kernel::types::CovariantForLt;
/// # fn expect_lt<F: CovariantForLt>() {}
/// # expect_lt::<
/// CovariantForLt!(fn(&u32)) // Contravariant, will fail compilation.
/// # >();
/// ```
///
/// There is a limitation if the type refers to generic parameters; if the macro cannot prove the
/// covariance syntactically, the emitted checks will fail the compilation as it needs to refer to
/// the generic parameter but is in a separate item.
///
/// ```
/// # use kernel::types::CovariantForLt;
/// fn expect_lt<F: CovariantForLt>() {}
/// # #[allow(clippy::unnecessary_safety_comment, reason = "false positive")]
/// fn generic_fn<T: 'static>() {
///     // Syntactically proven by the macro
///     expect_lt::<CovariantForLt!(&T)>();
///     // Syntactically proven by the macro
///     expect_lt::<CovariantForLt!(&KBox<T>)>();
///     // Cannot be syntactically proven, need to check covariance of `KBox`
///     // expect_lt::<CovariantForLt!(&KBox<&T>)>();
/// }
/// ```
///
/// # Safety
///
/// `Self::Of<'a>` must be covariant over the lifetime `'a`.
pub unsafe trait CovariantForLt: ForLt {
    /// Cast a reference to a shorter lifetime.
    #[inline(always)]
    fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Self::Of<'short> {
        // SAFETY: This is sound as this trait guarantees covariance.
        unsafe { core::mem::transmute(long) }
    }
}
pub use macros::CovariantForLt;

/// This is intended to be an "unsafe-to-refer-to" type.
///
/// Must only be used by the [`ForLt!`](macro@ForLt) / [`CovariantForLt!`](macro@CovariantForLt)
/// macros.
///
/// `T` is the magic `dyn for<'a> WithLt<'a, TypeThatUse<'a>>` generated by macro.
///
/// `WF` is a type that the macro can use to assert some specific type is well-formed.
///
/// `N` is to provide the macro a place to emit arbitrary items, in case it needs to prove
/// additional properties. [`ForLt!`](macro@ForLt) emits `N = 0`;
/// [`CovariantForLt!`](macro@CovariantForLt) emits `N = 1` after a covariance proof.
#[doc(hidden)]
pub struct UnsafeForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>);

// This is a helper trait for implementation of `ForLt` / `CovariantForLt` to be able to use HRTB.
#[doc(hidden)]
pub trait WithLt<'a> {
    type Of: 'a;
}

impl<T: ?Sized + for<'a> WithLt<'a>, WF, const N: usize> ForLt for UnsafeForLtImpl<T, WF, N> {
    type Of<'a> = <T as WithLt<'a>>::Of;
}

// SAFETY: In `CovariantForLt!` macro, a covariance proof is generated in the `N` const generic
// and it will fail to evaluate if the type is not covariant. Only `N = 1` gets this impl.
unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> CovariantForLt for UnsafeForLtImpl<T, WF, 1> {}