lazy_pinned/
lib.rs

1#![no_std]
2#![forbid(clippy::undocumented_unsafe_blocks)]
3
4//! See [`LazyPinned`].
5
6use core::pin::Pin;
7
8/// Pinned data which can be lazily initialized.
9///
10/// ## [`LazyPinned<T>`] vs. [`Option<T>`]
11///
12/// [`LazyPinned<T>`] act like [`Option<T>`].
13/// In fact, `LazyPinned<T>` is implemented by just wrapping `Option<T>`.
14/// However, they have different behaviors in pinning projection.
15///
16/// `Pin<P<Option<T>>>` guarantees the `Option<T>` is not moved,
17/// where `P<_>` is a pointer type which deref to `_`.
18/// Thus, when the data is `None`, it cannot be set to `Some(T)` unless
19/// `T: Unpin`.
20///
21/// `Pin<P<LazyPinned<T>>>` only guarantees the inner `T` is pinned.
22/// Thus, `Pin<&mut LazyPinned<T>>` optionally projects to `Pin<&mut T>`
23/// instead of `Pin<P<Option<T>>>`. When `Pin<P<LazyPinned<T>>>` is `None`,
24/// it can be initialized with a value of `T`.
25#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
26pub struct LazyPinned<T>(pub Option<T>);
27
28impl<T> Default for LazyPinned<T> {
29    #[inline]
30    fn default() -> Self {
31        Self(None)
32    }
33}
34
35impl<T> LazyPinned<T> {
36    #[inline]
37    #[must_use]
38    pub fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
39        Pin::get_ref(self).0.as_ref().map(|x| {
40            // SAFETY: `x` is guaranteed to be pinned because it comes from `self`
41            // which is pinned.
42            unsafe { Pin::new_unchecked(x) }
43        })
44    }
45
46    #[inline]
47    #[must_use]
48    pub fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
49        // SAFETY: `get_unchecked_mut` is never used to move the `Option` inside `self`.
50        // `x` is guaranteed to be pinned because it comes from `self` which is pinned.
51        unsafe {
52            Pin::get_unchecked_mut(self)
53                .0
54                .as_mut()
55                .map(|x| Pin::new_unchecked(x))
56        }
57    }
58
59    pub fn pin_project_or_insert(self: Pin<&mut Self>, v: T) -> Pin<&mut T> {
60        // SAFETY: `get_unchecked_mut` is never used to move the `Some(T)` inside `self`.
61        let this = unsafe { Pin::get_unchecked_mut(self) };
62        let x = this.0.get_or_insert(v);
63        // SAFETY: `x` is guaranteed to be pinned because it comes from `self` which is pinned.
64        unsafe { Pin::new_unchecked(x) }
65    }
66
67    pub fn pin_project_or_insert_with(self: Pin<&mut Self>, f: impl FnOnce() -> T) -> Pin<&mut T> {
68        // SAFETY: `get_unchecked_mut` is never used to move the `Some(T)` inside `self`.
69        let this = unsafe { Pin::get_unchecked_mut(self) };
70        let x = this.0.get_or_insert_with(f);
71        // SAFETY: `x` is guaranteed to be pinned because it comes from `self` which is pinned.
72        unsafe { Pin::new_unchecked(x) }
73    }
74
75    pub fn use_pin_or_insert(
76        self: Pin<&mut Self>,
77        use_pin: impl FnOnce(Pin<&mut T>),
78        v: T,
79    ) -> Pin<&mut T> {
80        self.use_pin_or_insert_with(use_pin, move || v)
81    }
82
83    pub fn use_pin_or_insert_with(
84        self: Pin<&mut Self>,
85        use_pin: impl FnOnce(Pin<&mut T>),
86        insert: impl FnOnce() -> T,
87    ) -> Pin<&mut T> {
88        // SAFETY: `get_unchecked_mut` is never used to move the `Some(T)` inside `self`.
89        let this = unsafe { Pin::get_unchecked_mut(self) };
90
91        match &mut this.0 {
92            Some(x) => {
93                // SAFETY: `x` is guaranteed to be pinned because it comes from `self` which is pinned.
94                let mut x = unsafe { Pin::new_unchecked(x) };
95                use_pin(x.as_mut());
96                x
97            }
98            this @ None => {
99                let x = this.insert(insert());
100
101                // SAFETY: `x` is guaranteed to be pinned because it comes from `self` which is pinned.
102                unsafe { Pin::new_unchecked(x) }
103            }
104        }
105    }
106
107    pub fn use_pin_or_insert_with_data<Data>(
108        self: Pin<&mut Self>,
109        data: Data,
110        use_pin: impl FnOnce(Data, Pin<&mut T>),
111        insert: impl FnOnce(Data) -> T,
112    ) -> Pin<&mut T> {
113        // SAFETY: `get_unchecked_mut` is never used to move the `Some(T)` inside `self`.
114        let this = unsafe { Pin::get_unchecked_mut(self) };
115
116        match &mut this.0 {
117            Some(x) => {
118                // SAFETY: `x` is guaranteed to be pinned because it comes from `self` which is pinned.
119                let mut x = unsafe { Pin::new_unchecked(x) };
120                use_pin(data, x.as_mut());
121                x
122            }
123            this @ None => {
124                let x = this.insert(insert(data));
125
126                // SAFETY: `x` is guaranteed to be pinned because it comes from `self` which is pinned.
127                unsafe { Pin::new_unchecked(x) }
128            }
129        }
130    }
131}