1#![no_std]
2
3#![feature(negative_impls)]
4
5use core::{
30 ops::Deref,
31 cmp::{
32 PartialEq,
33 PartialOrd,
34 Ordering
35 },
36 cell::UnsafeCell,
37 clone::Clone,
38 convert::AsRef,
39 fmt::{
40 Display,
41 Debug,
42 Formatter,
43 Error as FmtError
44 }
45};
46
47pub struct LateInit<T>(UnsafeCell<Option<T>>);
52
53unsafe impl <T> Sync for LateInit<T> {}
54impl <T> !Send for LateInit<T> {}
55
56impl <T> LateInit<T> {
57 pub const fn new() -> Self {
59 LateInit(UnsafeCell::new(None))
60 }
61
62 pub unsafe fn init(&self, value: T) {
64 assert!(self.option().is_none(), "LateInit.init called more than once");
65
66 *self.0.get() = Some(value);
67 }
68
69 #[inline(always)]
70 fn option(&self) -> &Option<T> {
71 unsafe { &*self.0.get() }
72 }
73
74 #[inline(always)]
75 fn data(&self) -> &T {
76 #[cfg(not(feature = "debug_unchecked"))] {
77 debug_assert!(self.option().is_some(), "LateInit used without initialization");
78 }
79
80 match self.option() {
81 Some(ref x) => x,
82 _ => unreachable!(),
83 }
84 }
85}
86
87impl <T: Clone> LateInit<T> {
88 #[inline(always)]
93 pub fn clone(&self) -> T {
94 self.data().clone()
95 }
96}
97
98impl <T> Deref for LateInit<T> {
99 type Target = T;
100
101 #[inline(always)]
103 fn deref(&self) -> &T {
104 self.data()
105 }
106}
107
108impl <T> AsRef<T> for LateInit<T> {
109 #[inline(always)]
111 fn as_ref(&self) -> &T {
112 self.data()
113 }
114}
115
116impl <T: PartialEq<W>, W> PartialEq<W> for LateInit<T> {
117 #[inline(always)]
118 fn eq(&self, other: &W) -> bool {
119 self.data().eq(other)
120 }
121
122 #[inline(always)]
123 fn ne(&self, other: &W) -> bool {
124 self.data().ne(other)
125 }
126}
127
128impl <T: PartialOrd<W>, W> PartialOrd<W> for LateInit<T> {
129 fn partial_cmp(&self, other: &W) -> Option<Ordering> {
130 self.data().partial_cmp(other)
131 }
132
133 fn lt(&self, other: &W) -> bool {
134 self.data().lt(other)
135 }
136
137 fn le(&self, other: &W) -> bool {
138 self.data().le(other)
139 }
140
141 fn gt(&self, other: &W) -> bool {
142 self.data().gt(other)
143 }
144
145 fn ge(&self, other: &W) -> bool {
146 self.data().ge(other)
147 }
148}
149
150impl <T: Debug> Debug for LateInit<T> {
151 fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
153 match self.option() {
154 Some(ref x) => { x.fmt(f) },
155 None => { write!(f, "<UNINITIALIZED>") },
156 }
157 }
158}
159
160impl <T: Display> Display for LateInit<T> {
161 fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
163 match self.option() {
164 Some(ref x) => { x.fmt(f) },
165 None => { write!(f, "<UNINITIALIZED>") },
166 }
167 }
168}
169
170#[cfg(test)]
171mod test {
172 use super::*;
173
174 use core::convert::AsRef;
175 use core::ops::Deref;
176
177 #[test]
178 #[should_panic]
179 #[cfg(not(feature = "debug_unchecked"))]
180 fn multiple_init_panics() {
181 let li = LateInit::<usize>::new();
182 unsafe {
183 li.init(4);
184 li.init(4);
185 }
186 }
187
188 #[test]
189 #[should_panic]
190 #[cfg(not(feature = "debug_unchecked"))]
191 fn as_ref_panics() {
192 let li = LateInit::<usize>::new();
193 let _ = li.as_ref();
194 }
195
196 #[test]
197 #[should_panic]
198 #[cfg(not(feature = "debug_unchecked"))]
199 fn deref_panics() {
200 let li = LateInit::<usize>::new();
201 let _ = li.deref();
202 }
203
204 #[test]
205 fn compare() {
206 let li = LateInit::<usize>::new();
207 unsafe { li.init(4); }
208
209 assert!(li > 3);
210 assert!(li < 5);
211 assert!(li >= 4);
212 assert!(li <= 4);
213 }
214
215 #[test]
216 #[should_panic]
217 #[cfg(not(feature = "debug_unchecked"))]
218 fn compare_panics() {
219 let li = LateInit::<usize>::new();
220 let _ = li > 4;
221 }
222
223 #[test]
224 fn eq() {
225 let li = LateInit::<usize>::new();
226 unsafe { li.init(4); }
227
228 assert_eq!(li, 4);
229 assert_ne!(li, 5);
230 }
231
232 #[test]
233 #[should_panic]
234 #[cfg(not(feature = "debug_unchecked"))]
235 fn eq_panics() {
236 let li = LateInit::<usize>::new();
237 let _ = li == 4;
238 }
239}