once_option/lib.rs
1//! The `once_option` crate defines a single type, [`struct@OnceOption`],
2//! with its constructing helper function, [`OnceOption()`].
3//!
4//! This crate is `no_std`.
5//!
6//! [`struct@OnceOption`] represents an optional value. Differently from
7//! [`Option`], an empty [`struct@OnceOption`] cannot be re-set to contain a
8//! value.
9//!
10//! Additionally, [`struct@OnceOption`] implements [`Deref`](std::ops::Deref)
11//! and [`DerefMut`](std::ops::DerefMut) so that its contents can be
12//! accessed without pattern-matching (but implicitly unwrapping).
13//!
14//! It supports comparisons ([`PartialEq`], [`Eq`], [`Ord`] or
15//! [`PartialOrd`]) with other [`struct@OnceOption`] containing the same type,
16//! as long as the contained type also implements those traits.
17//! Furthermore, it can be used as a hash key if the cotnained type
18//! is [`Hash`].
19//!
20//! It supports being displayed if the contained type is [`Display`](std::fmt::Display),
21//! and forwards all the formatting traits (except [`Debug`] and
22//! [`Pointer`](std::fmt::Pointer)) to its contained-type.
23//!
24//! # Rationale
25//!
26//! The main, but not only, purpose of [`struct@OnceOption`] is to simplify
27//! and regulate the dropping of members that have methods consuming
28//! the values.
29//!
30//! As an example, this code will fail to compile:
31//!
32//! ```compile_fail
33//! // Warning: this code does *NOT* compile
34//!
35//! use std::{thread, time::Duration};
36//!
37//! struct SomeType {
38//! handle: thread::JoinHandle<u32>,
39//! }
40//!
41//! impl SomeType {
42//! fn new() -> Self {
43//! Self {
44//! handle: thread::spawn(|| {
45//! thread::sleep(Duration::from_secs(5));
46//! 42
47//! }),
48//! }
49//! }
50//! }
51//!
52//! impl Drop for SomeType {
53//! fn drop(&mut self) {
54//! println!("The answer is {}", self.handle.join());
55//! }
56//! }
57//! ```
58//! The compiler will fail with an error like ([try it!](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=39a859f7169e43de84a01d67ec0ca685)):
59//!
60//! ```text
61//! Compiling playground v0.0.1 (/playground)
62//! error[E0507]: cannot move out of `self.handle` which is behind a mutable reference
63//! --> src/lib.rs:22:38
64//! |
65//! 22 | println!("The answer is {}", self.handle.join().unwrap());
66//! | ^^^^^^^^^^^ ------ `self.handle` moved due to this method call
67//! | |
68//! | move occurs because `self.handle` has type `JoinHandle<u32>`, which does not implement the `Copy` trait
69//! |
70//! note: `JoinHandle::<T>::join` takes ownership of the receiver `self`, which moves `self.handle`
71//! --> /playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/thread/mod.rs:1649:17
72//! |
73//! 1649 | pub fn join(self) -> Result<T> {
74//! | ^^^^
75//!
76//! For more information about this error, try `rustc --explain E0507`.
77//! error: could not compile `playground` (lib) due to 1 previous error
78//!
79//! ```
80//!
81//! [`struct@OnceOption`] can be used to fix the issue with minimal changes to the
82//! code:
83//!
84//! ```
85//! use once_option::OnceOption;
86//! use std::{thread, time::Duration};
87//!
88//! struct SomeType {
89//! handle: OnceOption<thread::JoinHandle<u32>>,
90//! }
91//!
92//! impl SomeType {
93//! fn new() -> Self {
94//! Self {
95//! handle: thread::spawn(|| {
96//! thread::sleep(Duration::from_secs(5));
97//! 42
98//! }).into(),
99//! }
100//! }
101//!
102//! fn thread_id(&self) -> thread::ThreadId {
103//! self.handle.thread().id()
104//! }
105//! }
106//!
107//! impl Drop for SomeType {
108//! fn drop(&mut self) {
109//! println!("The answer is {}", self.handle.take().join().unwrap());
110//! }
111//! }
112//! ```
113//! # Representation
114//! [`struct@OnceOption<T>`] has the same ABI of [`Option<T>`]; this means that
115//! [`struct@OnceOption<T>`] has the same size, alignment, and function call ABI as [`Option<T>`].
116//!
117//! An implication of this, is that all the ABI guarantees that [`Option<T>`] makes
118//! (i.e. being transmutable from a T under some conditions), also apply to
119//! [`struct@OnceOption<T>`]. For further details, see [the documentation for `Option`](core::option#representation).
120//!
121
122// We are no-std (docs and tests require std, though)
123#![no_std]
124
125#[cfg(test)]
126mod tests;
127
128#[cfg(any(test, doc))]
129#[macro_use]
130extern crate std;
131
132#[cfg(any(test, doc))]
133extern crate alloc;
134
135/// [`struct@OnceOption`] represents an optional value. Differently from [`Option`], an empty [`struct@OnceOption`] cannot be re-set to contain a value.
136///
137/// Check the [crate level documentation](self) for more details.
138#[repr(transparent)]
139#[derive(Copy, Clone, Ord, PartialOrd, PartialEq, Eq, Hash)]
140pub struct OnceOption<T> {
141 inner: Option<T>,
142}
143
144#[inline]
145#[allow(non_snake_case)]
146/// Builds a new [`struct@OnceOption`] containing (and owning) the specified `value`.
147///
148/// # Examples
149///
150/// ```
151/// # use once_option::OnceOption;
152/// let x: OnceOption<u32> = OnceOption(1912);
153/// assert_eq!(x.is_some(), true);
154/// ```
155#[must_use = "if you intend to immediately drop this value, consider using [`drop`] instead"]
156pub const fn OnceOption<T>(value: T) -> OnceOption<T> {
157 OnceOption { inner: Some(value) }
158}
159
160impl<T> OnceOption<T> {
161 /// A constant representing a [`struct@OnceOption`] that doesn't contain any value.
162 /// Since a [`struct@OnceOption`] cannot be set to contain a value after it has been
163 /// emptied, this constant is provided as a helper, but is of dubious utility.
164 ///
165 /// # Examples
166 ///
167 /// ```
168 /// # use once_option::OnceOption;
169 /// let x: OnceOption<u32> = OnceOption::NONE;
170 /// assert_eq!(x.is_some(), false);
171 /// ```
172 pub const NONE: Self = Self { inner: None };
173
174 /// Returns `true` if the once-option contains a value.
175 ///
176 /// # Examples
177 ///
178 /// ```
179 /// # use once_option::OnceOption;
180 /// let x: OnceOption<u32> = OnceOption(1912);
181 /// assert_eq!(x.is_some(), true);
182 ///
183 /// let x: OnceOption<u32> = OnceOption::NONE;
184 /// assert_eq!(x.is_some(), false);
185 /// ```
186 #[inline]
187 #[must_use = "if you intended to assert that this has a value, consider `.expect()` or `.unwrap()` instead"]
188 pub const fn is_some(&self) -> bool {
189 self.inner.is_some()
190 }
191
192 /// Returns `true` if the option is empty.
193 ///
194 /// # Examples
195 ///
196 /// ```
197 /// # use once_option::OnceOption;
198 /// let x: Option<u32> = Some(2);
199 /// assert_eq!(x.is_none(), false);
200 ///
201 /// let x: Option<u32> = None;
202 /// assert_eq!(x.is_none(), true);
203 /// ```
204 #[inline]
205 #[must_use = "if you intended to assert that this doesn't have a value, consider \
206 `.expect_none` instead"]
207 pub const fn is_none(&self) -> bool {
208 !self.is_some()
209 }
210
211 /// Returns the contained value, consuming the `self` value.
212 ///
213 /// # Panics
214 ///
215 /// Panics if the value is empty with a custom panic message provided by
216 /// `msg`.
217 ///
218 /// # Examples
219 ///
220 /// ```
221 /// # use once_option::OnceOption;
222 /// let x = OnceOption("value");
223 /// assert_eq!(x.expect("fruits are healthy"), "value");
224 /// ```
225 ///
226 /// ```should_panic
227 /// # use once_option::OnceOption;
228 /// let x = OnceOption::<&str>::NONE;
229 /// x.expect("fruits are healthy"); // panics with `fruits are healthy`
230 /// ```
231 #[inline]
232 #[track_caller]
233 pub fn expect(self, msg: &str) -> T {
234 self.inner.expect(msg)
235 }
236
237 /// Panics if the [`struct@OnceOption`] is not empty and does contain a value.
238 ///
239 /// # Panics
240 ///
241 /// Panics if the value is *not* empty, with a custom panic message provided by
242 /// `msg`.
243 ///
244 /// # Examples
245 ///
246 /// ```
247 /// # use once_option::OnceOption;
248 /// let x = OnceOption("value");
249 /// assert_eq!(x.expect("fruits are healthy"), "value");
250 /// ```
251 ///
252 /// ```should_panic
253 /// # use once_option::OnceOption;
254 /// let x = OnceOption::<&str>("something something");
255 /// x.expect_none("fruits are healthy"); // panics with `fruits are healthy`
256 /// ```
257 #[inline]
258 #[track_caller]
259 pub fn expect_none(self, msg: &str) {
260 if self.inner.is_some() {
261 panic!("{}", msg);
262 }
263 }
264
265 /// Takes the value out of the [`struct@OnceOption`], leaving it empty. If the
266 /// [`struct@OnceOption`] is already empty, this function will panic.
267 ///
268 /// Note that this operation cannot be reversed: once a [`struct@OnceOption`] becomes
269 /// empty, it cannot get a value again.
270 ///
271 /// # Examples
272 ///
273 /// ```
274 /// # use once_option::OnceOption;
275 /// let mut x = OnceOption(2);
276 /// let y = x.take();
277 /// assert!(x.is_none());
278 /// assert_eq!(y, 2);
279 /// ```
280 ///
281 /// ```should_panic
282 /// # use once_option::OnceOption;
283 /// let mut x = OnceOption(2);
284 /// let y = x.take();
285 /// let w = x.take(); // this panics!
286 /// ```
287 #[inline]
288 #[track_caller]
289 pub fn take(&mut self) -> T {
290 match self.inner.take() {
291 Some(value) => value,
292 None => Self::fail(),
293 }
294 }
295
296 /// Returns the contained value, consuming the `self` value. If the
297 /// [`struct@OnceOption`] is empty, this function will panic.
298 ///
299 /// # Examples
300 ///
301 /// ```
302 /// # use once_option::OnceOption;
303 /// let mut x = OnceOption(2);
304 /// assert_eq!(*x, 2);
305 /// x.replace(5);
306 /// assert_eq!(*x, 5);
307 /// ```
308 ///
309 /// ```should_panic
310 /// # use once_option::OnceOption;
311 /// let mut x: OnceOption<u32> = OnceOption::NONE;
312 /// x.unwrap(); // this panics!
313 /// ```
314 #[inline]
315 #[track_caller]
316 pub fn unwrap(self) -> T {
317 match self.inner {
318 Some(value) => value,
319 None => Self::fail(),
320 }
321 }
322
323 /// Replaces the actual value in the option by the value given in parameter,
324 /// returning the old value if present, or panic'ing otherwise.
325 ///
326 /// # Examples
327 ///
328 /// ```
329 /// # use once_option::OnceOption;
330 /// let mut x = OnceOption(2);
331 /// let old = x.replace(5);
332 /// assert_eq!(x.take(), 5);
333 /// assert_eq!(old, 2);
334 /// ```
335 ///
336 /// ```should_panic
337 /// # use once_option::OnceOption;
338 /// let mut x: OnceOption<i32> = OnceOption::NONE;
339 /// let _ = x.replace(3); // this panics
340 /// ```
341 #[inline]
342 pub fn replace(&mut self, value: T) -> T {
343 match self.inner.replace(value) {
344 None => Self::fail(),
345 Some(v) => v,
346 }
347 }
348
349 // Default failure method
350 fn fail() -> ! {
351 panic!(
352 "Value has been accessed on an empty once_option::OnceOption<{}>",
353 core::any::type_name::<T>()
354 )
355 }
356}
357
358impl<T> Default for OnceOption<T> {
359 /// Returns an empty [`struct@OnceOption`].
360 ///
361 /// # Examples
362 ///
363 /// ```
364 /// # use once_option::OnceOption;
365 /// let opt: OnceOption<u32> = OnceOption::default();
366 /// assert!(opt.is_none());
367 /// ```
368 #[inline]
369 fn default() -> OnceOption<T> {
370 Self::NONE
371 }
372}
373
374impl<T> From<T> for OnceOption<T> {
375 /// Moves `val` into a new [`struct@OnceOption`].
376 ///
377 /// # Examples
378 ///
379 /// ```
380 /// # use once_option::OnceOption;
381 /// let o: OnceOption<u8> = OnceOption::from(67);
382 ///
383 /// assert_eq!(67, *o);
384 /// ```
385 /// Alternatively:
386 /// ```
387 /// # use once_option::OnceOption;
388 /// let o: OnceOption<u8> = 67.into();
389 ///
390 /// assert_eq!(67, *o);
391 /// ```
392 #[inline]
393 fn from(val: T) -> OnceOption<T> {
394 OnceOption(val)
395 }
396}
397
398impl<T> From<Option<T>> for OnceOption<T> {
399 /// Moves an option `val` into a new [`struct@OnceOption`].
400 ///
401 /// # Examples
402 ///
403 /// ```
404 /// # use once_option::OnceOption;
405 /// let o: OnceOption<u8> = OnceOption::from(Some(67));
406 ///
407 /// assert_eq!(67, *o);
408 /// ```
409 #[inline]
410 fn from(val: Option<T>) -> OnceOption<T> {
411 Self { inner: val }
412 }
413}
414
415impl<T> core::ops::Deref for OnceOption<T> {
416 type Target = T;
417
418 fn deref(&self) -> &T {
419 match self.inner.as_ref() {
420 None => Self::fail(),
421 Some(r) => r,
422 }
423 }
424}
425
426impl<T> core::ops::DerefMut for OnceOption<T> {
427 fn deref_mut(&mut self) -> &mut T {
428 match self.inner.as_mut() {
429 None => Self::fail(),
430 Some(r) => r,
431 }
432 }
433}
434
435macro_rules! impl_formatting_trait {
436 ($TRAIT:ident) => {
437 impl<T: core::fmt::$TRAIT> core::fmt::$TRAIT for OnceOption<T> {
438 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
439 match &self.inner {
440 None => Self::fail(),
441 Some(v) => core::fmt::$TRAIT::fmt(v, f),
442 }
443 }
444 }
445 };
446}
447
448impl_formatting_trait!(Display);
449impl_formatting_trait!(UpperHex);
450impl_formatting_trait!(LowerHex);
451impl_formatting_trait!(Octal);
452impl_formatting_trait!(Binary);
453impl_formatting_trait!(LowerExp);
454impl_formatting_trait!(UpperExp);
455
456impl<T: core::fmt::Debug> core::fmt::Debug for OnceOption<T> {
457 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
458 match &self.inner {
459 None => f.write_str("OnceOption::NONE"),
460 Some(v) => {
461 f.write_str("OnceOption(")?;
462 core::fmt::Debug::fmt(v, f)?;
463 f.write_str(")")
464 }
465 }
466 }
467}