kernel/types/for_lt.rs
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> {}