lazy_wrap/
lib.rs

1use ::parking_lot::{ Once, OnceState };
2use ::std::cell::UnsafeCell;
3use ::std::mem::ManuallyDrop;
4use ::std::ops::{ Deref, DerefMut };
5use ::std::panic::{ RefUnwindSafe, UnwindSafe };
6use ::std::ptr;
7
8union Data<T, F> {
9	init: ManuallyDrop<F>,
10	value: ManuallyDrop<T>
11}
12
13pub struct LazyWrap<T, F = fn() -> T> {
14	data: UnsafeCell<Data<T, F>>,
15	once: Once
16}
17
18pub enum LazyWrapState<T, F> {
19	Initialised(T),
20	Uninitialised(F)
21}
22
23impl<T, F> LazyWrap<T, F>
24where
25	F: FnOnce() -> T
26{
27	#[inline]
28	pub const fn new(init: F) -> Self {
29		let init = ManuallyDrop::new(init);
30		let data = UnsafeCell::new(Data { init });
31		let once = Once::new();
32		Self { data, once }
33	}
34
35	#[inline]
36	pub fn ensure_initialised(this: &Self) {
37		this.once.call_once(|| {
38			let data = unsafe { &mut (*this.data.get()) };
39			let init = unsafe { ManuallyDrop::take(&mut data.init) };
40			let value = init();
41			data.value = ManuallyDrop::new(value);
42		});
43	}
44
45	#[inline]
46	fn ref_inner(this: &Self) -> &T {
47		Self::ensure_initialised(this);
48		unsafe { &(*this.data.get()).value }
49	}
50
51	#[inline]
52	fn mut_inner(this: &mut Self) -> &mut T {
53		Self::ensure_initialised(this);
54		unsafe { &mut (*this.data.get()).value }
55	}
56
57	#[inline]
58	pub fn is_initialised(this: &Self) -> bool {
59		use OnceState::*;
60		match this.once.state() {
61			New => { false }
62			Poisoned => { panic!("initialiser panicked") }
63			InProgress => {
64				this.once.call_once(|| {});
65				true
66			}
67			Done => { true }
68		}
69	}
70
71	pub fn into_inner(this: Self) -> LazyWrapState<T, F> {
72		let initialised = Self::is_initialised(&this);
73		let this = ManuallyDrop::new(this);
74		let data = unsafe { ptr::read(this.data.get()) };
75
76		if initialised {
77			let value = ManuallyDrop::into_inner(unsafe { data.value });
78			LazyWrapState::Initialised(value)
79		} else {
80			let init = ManuallyDrop::into_inner(unsafe { data.init });
81			LazyWrapState::Uninitialised(init)
82		}
83	}
84
85	pub fn into_inner_initialised(this: Self) -> T {
86		Self::ensure_initialised(&this);
87		let this = ManuallyDrop::new(this);
88		let data = unsafe { ptr::read(this.data.get()) };
89		ManuallyDrop::into_inner(unsafe { data.value })
90	}
91}
92
93impl<T, F> Deref for LazyWrap<T, F>
94where
95	F: FnOnce() -> T
96{
97	type Target = T;
98	#[inline]
99	fn deref(&self) -> &Self::Target {
100		// ensure_initialised is called by ref_inner
101		Self::ref_inner(self)
102	}
103}
104
105impl<T, F> DerefMut for LazyWrap<T, F>
106where
107	F: FnOnce() -> T
108{
109	#[inline]
110	fn deref_mut(&mut self) -> &mut Self::Target {
111		// ensure_initialised is called by mut_inner
112		Self::mut_inner(self)
113	}
114}
115
116impl<T, U, F> AsRef<U> for LazyWrap<T, F>
117where
118	F: FnOnce() -> T,
119	T: AsRef<U>,
120	U: ?Sized
121{
122	#[inline]
123	fn as_ref(&self) -> &U {
124		// ensure_initialised called by Deref
125		(**self).as_ref()
126	}
127}
128
129impl<T, U, F> AsMut<U> for LazyWrap<T, F>
130where
131	F: FnOnce() -> T,
132	T: AsMut<U>,
133	U: ?Sized
134{
135	#[inline]
136	fn as_mut(&mut self) -> &mut U {
137		// ensure_initialised called by DerefMut
138		(**self).as_mut()
139	}
140}
141
142unsafe impl<T, F> Send for LazyWrap<T, F> where T: Send, F: Send {}
143unsafe impl<T, F> Sync for LazyWrap<T, F> where T: Sync, F: Send {}
144impl<T, F> UnwindSafe for LazyWrap<T, F> where T: UnwindSafe, F: UnwindSafe {}
145impl<T, F> RefUnwindSafe for LazyWrap<T, F> where T: RefUnwindSafe, F: UnwindSafe {}
146impl<T, F> Unpin for LazyWrap<T, F> where T: Unpin, F: Unpin {}
147
148impl<T, F> Drop for LazyWrap<T, F> {
149	fn drop(&mut self) {
150		use OnceState::*;
151		match self.once.state() {
152			New => {
153				unsafe { ManuallyDrop::drop(&mut self.data.get_mut().init) }
154			}
155			Poisoned => {}
156			InProgress => {
157				// ???
158				// lets drop the thing once its done just in case
159				// this cannot happen though. if we're dropping, we're the last one with a reference.
160
161				self.once.call_once(|| {});
162				unsafe { ManuallyDrop::drop(&mut self.data.get_mut().value) }
163			}
164			Done => {
165				unsafe { ManuallyDrop::drop(&mut self.data.get_mut().value) }
166			}
167		}
168	}
169}