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
// SPDX-License-Identifier: Apache-2.0 OR MIT
//! Provide implementation and test of the `ForLt` trait and macro.
//!
//! This module is hidden and user should just use `ForLt!` directly.
use core::marker::PhantomData;
/// Representation of types generic over a lifetime.
///
/// The type must be covariant over the generic lifetime, i.e. the lifetime parameter
/// can be soundly shortened.
///
/// The lifetime involved must be covariant.
///
/// # Macro
///
/// It is not recommended to implement this trait directly. `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)`.
/// # >();
/// ```
///
/// 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::ForLt;
/// # fn expect_lt<F: ForLt>() {}
/// # expect_lt::<
/// ForLt!(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::ForLt;
/// fn expect_lt<F: ForLt>() {}
/// # #[allow(clippy::unnecessary_safety_comment, reason = "false positive")]
/// fn generic_fn<T: 'static>() {
/// // Syntactically proven by the macro
/// expect_lt::<ForLt!(&T)>();
/// // Syntactically proven by the macro
/// expect_lt::<ForLt!(&KBox<T>)>();
/// // Cannot be syntactically proven, need to check covariance of `KBox`
/// // expect_lt::<ForLt!(&KBox<&T>)>();
/// }
/// ```
///
/// # Safety
///
/// `Self::Of<'a>` must be covariant over the lifetime `'a`.
pub unsafe trait ForLt {
/// The type parameterized by the lifetime.
type Of<'a>: 'a;
/// 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::ForLt;
/// This is intended to be an "unsafe-to-refer-to" type.
///
/// Must only be used by the `ForLt!` macro.
///
/// `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.
#[doc(hidden)]
pub struct UnsafeForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>);
// This is a helper trait for implementation `ForLt` to be able to use HRTB.
#[doc(hidden)]
pub trait WithLt<'a> {
type Of: 'a;
}
// SAFETY: In `ForLt!` macro, a covariance proof is generated when naming `UnsafeForLtImpl`
// and it will fail to evaluate if the type is not covariant.
unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> ForLt for UnsafeForLtImpl<T, WF, 0> {
type Of<'a> = <T as WithLt<'a>>::Of;
}