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) }
            }
        }
    }
}