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}