call_once/lib.rs
1//! This crate provides [`CallOnce`], a simple, thread-safe type that can only be called successfully _once_:
2//!
3//! ```
4//! use call_once::CallOnce;
5//!
6//! static CALL_ONCE: CallOnce = CallOnce::new();
7//!
8//! assert!(CALL_ONCE.call_once().is_ok());
9//! assert!(CALL_ONCE.call_once().is_err());
10//! ```
11
12#![no_std]
13
14use core::fmt;
15use core::sync::atomic::{AtomicBool, Ordering};
16
17/// A type that can only be called successfully _once_.
18///
19/// This is a simple wrapper around an [`AtomicBool`] with a more descriptive API.
20///
21/// <div class="warning">
22/// While <code>CallOnce</code> is synchronized and thread-safe, it does not synchronize other memory accesses.
23/// </div>
24///
25/// # Examples
26///
27/// ```
28/// use call_once::CallOnce;
29///
30/// static CALL_ONCE: CallOnce = CallOnce::new();
31///
32/// assert!(CALL_ONCE.call_once().is_ok());
33/// assert!(CALL_ONCE.call_once().is_err());
34/// ```
35#[derive(Default, Debug)]
36pub struct CallOnce {
37 called: AtomicBool,
38}
39
40impl CallOnce {
41 /// Creates a new `CallOnce`.
42 ///
43 /// # Examples
44 ///
45 /// ```
46 /// use call_once::CallOnce;
47 ///
48 /// let call_once = CallOnce::new();
49 /// ```
50 #[inline]
51 pub const fn new() -> Self {
52 Self {
53 called: AtomicBool::new(false),
54 }
55 }
56
57 /// Mark this `CallOnce` as called.
58 ///
59 /// Only the first call returns `Ok`.
60 /// All subsequent calls return `Err`.
61 ///
62 /// # Examples
63 ///
64 /// ```
65 /// use call_once::CallOnce;
66 ///
67 /// let call_once = CallOnce::new();
68 ///
69 /// assert!(call_once.call_once().is_ok());
70 /// assert!(call_once.call_once().is_err());
71 /// ```
72 #[inline]
73 pub fn call_once(&self) -> Result<(), CallOnceError> {
74 self.called
75 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
76 .map(drop)
77 .map_err(|_| CallOnceError)
78 }
79
80 /// Returns `true` if `call_once` has been called.
81 ///
82 /// # Examples
83 ///
84 /// ```
85 /// use call_once::CallOnce;
86 ///
87 /// let call_once = CallOnce::new();
88 /// assert!(!call_once.was_called());
89 ///
90 /// call_once.call_once().unwrap();
91 /// assert!(call_once.was_called());
92 /// ```
93 #[inline]
94 pub fn was_called(&self) -> bool {
95 self.called.load(Ordering::Relaxed)
96 }
97}
98
99/// The `CallOnceError` error indicates that [`CallOnce::call_once`] has been called more than once.
100#[derive(Debug)]
101pub struct CallOnceError;
102
103impl fmt::Display for CallOnceError {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 f.write_str("call_once was executed more than once")
106 }
107}