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
#![no_std]
#![forbid(clippy::undocumented_unsafe_blocks)]
//! See [`LazyPinned`].
use core::pin::Pin;
/// Pinned data which can be lazily initialized.
///
/// ## [`LazyPinned<T>`] vs. [`Option<T>`]
///
/// [`LazyPinned<T>`] act like [`Option<T>`].
/// In fact, `LazyPinned<T>` is implemented by just wrapping `Option<T>`.
/// However, they have different behaviors in pinning projection.
///
/// `Pin<P<Option<T>>>` guarantees the `Option<T>` is not moved,
/// where `P<_>` is a pointer type which deref to `_`.
/// Thus, when the data is `None`, it cannot be set to `Some(T)` unless
/// `T: Unpin`.
///
/// `Pin<P<LazyPinned<T>>>` only guarantees the inner `T` is pinned.
/// Thus, `Pin<&mut LazyPinned<T>>` optionally projects to `Pin<&mut T>`
/// instead of `Pin<P<Option<T>>>`. When `Pin<P<LazyPinned<T>>>` is `None`,
/// it can be initialized with a value of `T`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LazyPinned<T>(pub Option<T>);
impl<T> Default for LazyPinned<T> {
#[inline]
fn default() -> Self {
Self(None)
}
}
impl<T> LazyPinned<T> {
#[inline]
#[must_use]
pub fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
Pin::get_ref(self).0.as_ref().map(|x| {
// SAFETY: `x` is guaranteed to be pinned because it comes from `self`
// which is pinned.
unsafe { Pin::new_unchecked(x) }
})
}
#[inline]
#[must_use]
pub fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
// SAFETY: `get_unchecked_mut` is never used to move the `Option` inside `self`.
// `x` is guaranteed to be pinned because it comes from `self` which is pinned.
unsafe {
Pin::get_unchecked_mut(self)
.0
.as_mut()
.map(|x| Pin::new_unchecked(x))
}
}
pub fn pin_project_or_insert(self: Pin<&mut Self>, v: T) -> Pin<&mut T> {
// SAFETY: `get_unchecked_mut` is never used to move the `Some(T)` inside `self`.
let this = unsafe { Pin::get_unchecked_mut(self) };
let x = this.0.get_or_insert(v);
// SAFETY: `x` is guaranteed to be pinned because it comes from `self` which is pinned.
unsafe { Pin::new_unchecked(x) }
}
pub fn pin_project_or_insert_with(self: Pin<&mut Self>, f: impl FnOnce() -> T) -> Pin<&mut T> {
// SAFETY: `get_unchecked_mut` is never used to move the `Some(T)` inside `self`.
let this = unsafe { Pin::get_unchecked_mut(self) };
let x = this.0.get_or_insert_with(f);
// SAFETY: `x` is guaranteed to be pinned because it comes from `self` which is pinned.
unsafe { Pin::new_unchecked(x) }
}
pub fn use_pin_or_insert(
self: Pin<&mut Self>,
use_pin: impl FnOnce(Pin<&mut T>),
v: T,
) -> Pin<&mut T> {
self.use_pin_or_insert_with(use_pin, move || v)
}
pub fn use_pin_or_insert_with(
self: Pin<&mut Self>,
use_pin: impl FnOnce(Pin<&mut T>),
insert: impl FnOnce() -> T,
) -> Pin<&mut T> {
// SAFETY: `get_unchecked_mut` is never used to move the `Some(T)` inside `self`.
let this = unsafe { Pin::get_unchecked_mut(self) };
match &mut this.0 {
Some(x) => {
// SAFETY: `x` is guaranteed to be pinned because it comes from `self` which is pinned.
let mut x = unsafe { Pin::new_unchecked(x) };
use_pin(x.as_mut());
x
}
this @ None => {
let x = this.insert(insert());
// SAFETY: `x` is guaranteed to be pinned because it comes from `self` which is pinned.
unsafe { Pin::new_unchecked(x) }
}
}
}
pub fn use_pin_or_insert_with_data<Data>(
self: Pin<&mut Self>,
data: Data,
use_pin: impl FnOnce(Data, Pin<&mut T>),
insert: impl FnOnce(Data) -> T,
) -> Pin<&mut T> {
// SAFETY: `get_unchecked_mut` is never used to move the `Some(T)` inside `self`.
let this = unsafe { Pin::get_unchecked_mut(self) };
match &mut this.0 {
Some(x) => {
// SAFETY: `x` is guaranteed to be pinned because it comes from `self` which is pinned.
let mut x = unsafe { Pin::new_unchecked(x) };
use_pin(data, x.as_mut());
x
}
this @ None => {
let x = this.insert(insert(data));
// SAFETY: `x` is guaranteed to be pinned because it comes from `self` which is pinned.
unsafe { Pin::new_unchecked(x) }
}
}
}
}