Skip to main content

kernel/types/
for_lt.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3//! Provide implementation and test of the `ForLt` trait and macro.
4//!
5//! This module is hidden and user should just use `ForLt!` directly.
6
7use core::marker::PhantomData;
8
9/// Representation of types generic over a lifetime.
10///
11/// The type must be covariant over the generic lifetime, i.e. the lifetime parameter
12/// can be soundly shortened.
13///
14/// The lifetime involved must be covariant.
15///
16/// # Macro
17///
18/// It is not recommended to implement this trait directly. `ForLt!` macro is provided to obtain a
19/// type that implements this trait.
20///
21/// The full syntax is
22///
23/// ```
24/// # use kernel::types::ForLt;
25/// # fn expect_lt<F: ForLt>() {}
26/// # struct TypeThatUse<'a>(&'a ());
27/// # expect_lt::<
28/// ForLt!(for<'a> TypeThatUse<'a>)
29/// # >();
30/// ```
31///
32/// which gives a type so that `<ForLt!(for<'a> TypeThatUse<'a>) as ForLt>::Of<'b>`
33/// is `TypeThatUse<'b>`.
34///
35/// You may also use a short-hand syntax which works similar to lifetime elision.
36/// The macro also accepts types that do not involve a lifetime at all.
37///
38/// ```
39/// # use kernel::types::ForLt;
40/// # fn expect_lt<F: ForLt>() {}
41/// # struct TypeThatUse<'a>(&'a ());
42/// # expect_lt::<
43/// ForLt!(TypeThatUse<'_>) // Equivalent to `ForLt!(for<'a> TypeThatUse<'a>)`.
44/// # >();
45/// # expect_lt::<
46/// ForLt!(&u32) // Equivalent to `ForLt!(for<'a> &'a u32)`.
47/// # >();
48/// # expect_lt::<
49/// ForLt!(u32) // Equivalent to `ForLt!(for<'a> u32)`.
50/// # >();
51/// ```
52///
53/// The macro will attempt to prove that the type is indeed covariant over the lifetime supplied.
54/// When it cannot be syntactically proven, it will emit checks to ask the Rust compiler to prove
55/// it.
56///
57/// ```ignore,compile_fail
58/// # use kernel::types::ForLt;
59/// # fn expect_lt<F: ForLt>() {}
60/// # expect_lt::<
61/// ForLt!(fn(&u32)) // Contravariant, will fail compilation.
62/// # >();
63/// ```
64///
65/// There is a limitation if the type refers to generic parameters; if the macro cannot prove the
66/// covariance syntactically, the emitted checks will fail the compilation as it needs to refer to
67/// the generic parameter but is in a separate item.
68///
69/// ```
70/// # use kernel::types::ForLt;
71/// fn expect_lt<F: ForLt>() {}
72/// # #[allow(clippy::unnecessary_safety_comment, reason = "false positive")]
73/// fn generic_fn<T: 'static>() {
74///     // Syntactically proven by the macro
75///     expect_lt::<ForLt!(&T)>();
76///     // Syntactically proven by the macro
77///     expect_lt::<ForLt!(&KBox<T>)>();
78///     // Cannot be syntactically proven, need to check covariance of `KBox`
79///     // expect_lt::<ForLt!(&KBox<&T>)>();
80/// }
81/// ```
82///
83/// # Safety
84///
85/// `Self::Of<'a>` must be covariant over the lifetime `'a`.
86pub unsafe trait ForLt {
87    /// The type parameterized by the lifetime.
88    type Of<'a>: 'a;
89
90    /// Cast a reference to a shorter lifetime.
91    #[inline(always)]
92    fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Self::Of<'short> {
93        // SAFETY: This is sound as this trait guarantees covariance.
94        unsafe { core::mem::transmute(long) }
95    }
96}
97pub use macros::ForLt;
98
99/// This is intended to be an "unsafe-to-refer-to" type.
100///
101/// Must only be used by the `ForLt!` macro.
102///
103/// `T` is the magic `dyn for<'a> WithLt<'a, TypeThatUse<'a>>` generated by macro.
104///
105/// `WF` is a type that the macro can use to assert some specific type is well-formed.
106///
107/// `N` is to provide the macro a place to emit arbitrary items, in case it needs to prove
108/// additional properties.
109#[doc(hidden)]
110pub struct UnsafeForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>);
111
112// This is a helper trait for implementation `ForLt` to be able to use HRTB.
113#[doc(hidden)]
114pub trait WithLt<'a> {
115    type Of: 'a;
116}
117
118// SAFETY: In `ForLt!` macro, a covariance proof is generated when naming `UnsafeForLtImpl`
119// and it will fail to evaluate if the type is not covariant.
120unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> ForLt for UnsafeForLtImpl<T, WF, 0> {
121    type Of<'a> = <T as WithLt<'a>>::Of;
122}