wiwi/lazy_wrap.rs
1extern crate parking_lot;
2
3use crate::prelude::*;
4use parking_lot::{ Once, OnceState };
5
6/// Inner data union
7///
8/// Note: in implementation of [`LazyWrap`], the "discriminant" is held by its
9/// [`Once`] instance
10union Data<T, F> {
11 /// Initialisation function
12 init: ManuallyDrop<F>,
13
14 /// Initialised value (from initialisation function)
15 value: ManuallyDrop<T>
16}
17
18/// A lazily initialised data wrapper that initialises itself on first access
19pub struct LazyWrap<T, F = fn() -> T> {
20 /// The data, either the initialisation function or the initialised value
21 ///
22 /// Note: state is kept track of in [`once`](LazyWrap::once)
23 data: UnsafeCell<Data<T, F>>,
24
25 /// The [`Once`] instance responsible for syncronising references,
26 /// ensuring the provided initialisation function is only taken/called once,
27 /// and holding the state of the [data union](LazyWrap::data)
28 once: Once
29}
30
31/// Returned by [`LazyWrap::into_inner`], containing the initialised value if
32/// its already initialised, or otherwise the initialisation function.
33pub enum LazyWrapState<T, F> {
34 /// Contains previously initialised value
35 Initialised(T),
36 /// Value is not initialised, contains initialisation function.
37 Uninitialised(F)
38}
39
40impl<T, F> LazyWrap<T, F>
41where
42 F: FnOnce() -> T
43{
44 /// Creates a new uninitialised instance that will be initialised with the
45 /// provided initialisation function.
46 #[inline]
47 pub const fn new(init: F) -> Self {
48 let init = ManuallyDrop::new(init);
49
50 // `Once` instance is just initialised, and data enum instance holds
51 // the init fn
52 let data = UnsafeCell::new(Data { init });
53 let once = Once::new();
54
55 Self { data, once }
56 }
57
58 /// Runs initialisation if the value is not initialised yet, and
59 /// blocks until it is complete.
60 ///
61 /// Note: [`Deref`] and [`DerefMut`] automatically initialise if necessary.
62 #[inline]
63 pub fn ensure_initialised(this: &Self) {
64 this.once.call_once(|| {
65 // SAFETY: `Once` ensures only one closure is only being run in one thread
66 // at a time, and this is the only code site that uses `call_once`
67 // (ie. if this closure is running / we're in this closure,
68 // it's guaranteed that no other closures are being run), so its safe
69 // to get a reference to the UnsafeCell contents
70 let data = unsafe { &mut *this.data.get() };
71
72 // SAFETY: `Once` ensures this closure is only called once, globally,
73 // per `LazyWrap` instance, so the data in here must be the
74 // initialisation function
75 let init = unsafe { ManuallyDrop::take(&mut data.init) };
76
77 let value = init();
78 data.value = ManuallyDrop::new(value);
79 });
80 }
81
82 /// Ensures the inner value is initialised, then
83 /// gets a reference to it
84 #[inline]
85 fn ref_inner(this: &Self) -> &T {
86 Self::ensure_initialised(this);
87
88 // SAFETY: we have immutable borrow access to the data (guaranteed by rust
89 // type system), and so can create an immutable reference to the data
90 // within the `UnsafeCell`
91 let data = unsafe { &*this.data.get() };
92
93 // SAFETY: we just ensured initialised earlier in this fn,
94 // so accessing the data from `value` is sound
95 unsafe { &data.value }
96 }
97
98 /// Ensures the inner value is initialised, then
99 /// gets a mut reference to it
100 #[inline]
101 fn mut_inner(this: &mut Self) -> &mut T {
102 Self::ensure_initialised(this);
103
104 // SAFETY: we have mut borrow access to the data (guaranteed by rust
105 // type system), and so can create a mut reference to the data
106 // within the `UnsafeCell`
107 let data = unsafe { &mut *this.data.get() };
108
109 // SAFETY: we just ensured initialised earlier in this fn,
110 // so accessing the data from `value` is sound
111 unsafe { &mut data.value }
112 }
113
114 /// Returns true or false, depending on if the value is initialised.
115 ///
116 /// # Panics
117 ///
118 /// Panics if the provided initialisation function panicked.
119 #[inline]
120 pub fn is_initialised(this: &Self) -> bool {
121 use OnceState::*;
122 match this.once.state() {
123 New => { false }
124 Poisoned => { panic!("initialiser panicked") }
125 InProgress => {
126 this.once.call_once(|| {});
127 true
128 }
129 Done => { true }
130 }
131 }
132
133 /// Fetch the value if its initialised, or return the initialisation function
134 /// if it isn't.
135 #[inline]
136 pub fn into_inner(this: Self) -> LazyWrapState<T, F> {
137 let this = ManuallyDrop::new(this);
138
139 // SAFETY: we own `this` and have wrapped it in `ManuallyDrop` to
140 // prevent double drops, and so taking this will be the only copy of data.
141 // Additionally we wrapped it before taking it, so if `Self::is_initialised`
142 // panicks there's no issue there
143 let data = unsafe { ptr::read(this.data.get()) };
144
145 if Self::is_initialised(&this) {
146 // SAFETY: `this` is initialised (checked by if statement),
147 // so `data` will contain the initialised value
148 // and accessing it is sound
149 let value = unsafe { data.value };
150
151 let value = ManuallyDrop::into_inner(value);
152 LazyWrapState::Initialised(value)
153 } else {
154 // SAFETY: `this` is not initialised (checked by if statement),
155 // so `init` will contain the initialisation function
156 // and accessing it is sound
157 let init = unsafe { data.init };
158
159 let init = ManuallyDrop::into_inner(init);
160 LazyWrapState::Uninitialised(init)
161 }
162 }
163
164 /// Ensures that the value is initialised, then returns the value.
165 #[inline]
166 pub fn into_inner_initialised(this: Self) -> T {
167 Self::ensure_initialised(&this);
168 let this = ManuallyDrop::new(this);
169
170 // SAFETY: we own `this` and have wrapped it in `ManuallyDrop` to
171 // prevent double drops, and so taking this will be the only copy of data.
172 // Additionally we wrapped it before taking it, so if `Self::is_initialised`
173 // panicks there's no issue there
174 let data = unsafe { ptr::read(this.data.get()) };
175
176 // SAFETY: we just ensured initialised earlier in this fn,
177 // so accessing the data from `value` is sound
178 let value = unsafe { data.value };
179
180 ManuallyDrop::into_inner(value)
181 }
182}
183
184impl<T, F> Deref for LazyWrap<T, F>
185where
186 F: FnOnce() -> T
187{
188 type Target = T;
189 #[inline]
190 fn deref(&self) -> &Self::Target {
191 // ensure_initialised is called by ref_inner
192 Self::ref_inner(self)
193 }
194}
195
196impl<T, F> DerefMut for LazyWrap<T, F>
197where
198 F: FnOnce() -> T
199{
200 #[inline]
201 fn deref_mut(&mut self) -> &mut Self::Target {
202 // ensure_initialised is called by mut_inner
203 Self::mut_inner(self)
204 }
205}
206
207impl<T, U, F> AsRef<U> for LazyWrap<T, F>
208where
209 F: FnOnce() -> T,
210 T: AsRef<U>,
211 U: ?Sized
212{
213 #[inline]
214 fn as_ref(&self) -> &U {
215 // ensure_initialised called by Deref
216 (**self).as_ref()
217 }
218}
219
220impl<T, U, F> AsMut<U> for LazyWrap<T, F>
221where
222 F: FnOnce() -> T,
223 T: AsMut<U>,
224 U: ?Sized
225{
226 #[inline]
227 fn as_mut(&mut self) -> &mut U {
228 // ensure_initialised called by DerefMut
229 (**self).as_mut()
230 }
231}
232
233// SAFETY: `LazyWrap` is `Send` if `T` and `F` are both `Send`.
234// Sending `LazyWrap` across threads can cause both `T` and `F` to be sent.
235// `F` can be sent to and run on another thread, so `F` must also be `Send`.
236unsafe impl<T, F> Send for LazyWrap<T, F>
237where
238 T: Send,
239 F: Send
240{}
241
242// SAFETY: `LazyWrap` is `Sync` if `T` is `Sync` and `F` is `Send`.
243// Sharing `LazyWrap` across threads can cause `T` to be shared. `F` may be
244// run on the other thread via the shared reference if `LazyWrap` hasn't been
245// initialised/accessed yet, so `F` must be `Send`.
246unsafe impl<T, F> Sync for LazyWrap<T, F>
247where
248 T: Sync,
249 F: Send
250{}
251
252// `UnwindSafe` if `T` and `F` are both `UnwindSafe`.
253// Sending `LazyWrap` across an unwind boundary will send `T` and `F` both. `T`
254// may be accessed and `F` may be called across an unwind boundary, and code may
255// panic while both is happening, so both `T` and `F` must be `UnwindSafe`.
256impl<T, F> UnwindSafe for LazyWrap<T, F>
257where
258 T: UnwindSafe,
259 F: UnwindSafe
260{}
261
262// `RefUnwindSafe` if `T` is `RefUnwindSafe` and `F` is `UnwindSafe`.
263// Sending references of `LazyWrap` will send `T` as a reference across. `F`
264// may be run and panic on the other side of the boundary if `LazyWrap` hasn't
265// been initialised yet, so must be `UnwindSafe`.
266impl<T, F> RefUnwindSafe for LazyWrap<T, F>
267where
268 T: RefUnwindSafe,
269 F: UnwindSafe
270{}
271
272// `Unpin` if `T` and `F` are both `Unpin`.
273// If either `T` or `F` cannot move, we cannot move either
274// (ie. cannot implement Unpin).
275impl<T, F> Unpin for LazyWrap<T, F>
276where
277 T: Unpin,
278 F: Unpin
279{}
280
281impl<T, F> Debug for LazyWrap<T, F>
282where
283 T: Debug,
284 F: FnOnce() -> T
285{
286 #[inline]
287 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288 if Self::is_initialised(self) {
289 f.debug_struct("LazyWrap")
290 .field("initialised", &true)
291 .field("data", &**self)
292 .finish()
293 } else {
294 f.debug_struct("LazyWrap")
295 .field("initialised", &false)
296 .finish_non_exhaustive()
297 }
298 }
299}
300
301impl<T, F> Display for LazyWrap<T, F>
302where
303 T: Display,
304 F: FnOnce() -> T
305{
306 #[inline]
307 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308 Display::fmt(&**self, f)
309 }
310}
311
312impl<T, F> Drop for LazyWrap<T, F> {
313 #[inline]
314 fn drop(&mut self) {
315 use OnceState::*;
316 match self.once.state() {
317 New => {
318 // SAFETY: `self.once` has not been run yet, so this must be
319 // the initialisation function, so this field access must be sound
320 let init = unsafe { &mut self.data.get_mut().init };
321
322 // SAFETY: no one has dropped `init` before, and we are in drop hook,
323 // so no one can drop after
324 unsafe { ManuallyDrop::drop(init) }
325 }
326 Poisoned => {
327 // just let it drop without panicking again I guess..
328 }
329 InProgress => {
330 // ???
331
332 // lets wait on `call_once`, then drop the thing, just in case
333 // this cannot happen though. if we're dropping, we're the last one with a reference.
334 self.once.call_once(|| {});
335
336 // SAFETY: `self.once` has been run, so this must be
337 // the initialised value, so this field access must be sound
338 let value = unsafe { &mut self.data.get_mut().value };
339
340 // SAFETY: no one has dropped `value` before, and we are in drop hook,
341 // so no one can drop after
342 unsafe { ManuallyDrop::drop(value) }
343 }
344 Done => {
345 // SAFETY: `self.once` has been run, so this must be
346 // the initialised value, so this field access must be sound
347 let value = unsafe { &mut self.data.get_mut().value };
348
349 // SAFETY: no one has dropped `value` before, and we are in drop hook,
350 // so no one can drop after
351 unsafe { ManuallyDrop::drop(value) }
352 }
353 }
354 }
355}