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}