takecell/lib.rs
1//! This crate provides two new cell-like types, `TakeCell` and `TakeOwnCell`.
2//! Both may store arbitrary non-`Copy` types, can be read from at most once and
3//! provide direct unique access to the stored contents. The core API looks
4//! roughly like this (and there’s much more inside, read on!):
5//! ```rust,ignore
6//! impl<T> TakeCell<T> {
7//! const fn new(v: T) -> Self { ... }
8//! }
9//! impl<T: ?Sized> TakeCell<T> {
10//! fn take(&self) -> Option<&mut T> { ... }
11//! }
12//!
13//! impl<T> TakeOwnCell<T> {
14//! const fn new(v: T) -> Self { ... }
15//! fn take(&self) -> Option<T> { ... }
16//! }
17//! ```
18//! Note that, like with `RefCell` and `Mutex`, the `take` method requires only
19//! a shared reference. Because of the single read restriction `take` can
20//! return a `&mut T` or `T` instead of `RefMut<T>` or `MutexGuard<T>`. In some
21//! sense `TakeCell` can be thought as a `Mutex` without unlocking (or rather
22//! with unlocking requiring unique access to the `Mutex`, see [`heal`]).
23//!
24//! [`heal`]: TakeCell::heal
25//!
26//! This crate is `#![no_std]` and only requires little sychronization via 8-bit
27//! atomic.
28//!
29//! ## Usage examples
30//!
31//! ### Singletons
32//!
33//! `TakeCell` is `Sync` (when `T: Sync`) and as such it may be used in
34//! `static`s. This can be used to create singletons:
35//!
36//! ```
37//! use takecell::TakeCell;
38//!
39//! #[non_exhaustive]
40//! pub struct Peripherals {
41//! pub something: Something,
42//! }
43//!
44//! pub static PEREPHERALS: TakeCell<Peripherals> = TakeCell::new(Peripherals {
45//! something: Something,
46//! });
47//! # pub struct Something;
48//!
49//! let peripherals: &'static mut _ = PEREPHERALS.take().unwrap();
50//! ```
51//!
52//! ### Doing work only once
53//!
54//! ```
55//! use once_cell::sync::OnceCell;
56//! use std::sync::{Arc, Condvar, Mutex};
57//! use takecell::TakeCell;
58//!
59//! #[derive(Clone)]
60//! struct Job {
61//! // Input can be a type which requires unique access to be used (e.g.: `dyn Read`)
62//! input: Arc<TakeCell<Input>>,
63//! output: Arc<OnceCell<Output>>,
64//! wait: Arc<(Mutex<bool>, Condvar)>,
65//! }
66//!
67//! fn execute(job: Job) -> Output {
68//! match job.input.take() {
69//! Some(input) => {
70//! // Nobody has started executing the job yet, so execute it
71//! let output = input.process();
72//!
73//! // Write the output
74//! job.output.set(output);
75//!
76//! // Notify other threads that the job is done
77//! let (lock, cvar) = &*job.wait;
78//! let mut done = lock.lock().unwrap();
79//! *done = true;
80//! }
81//! None => {
82//! // Wait for the other thread to do the job
83//! let (lock, cvar) = &*job.wait;
84//! let mut done = lock.lock().unwrap();
85//! // As long as the value inside the `Mutex<bool>` is `false`, we wait
86//! while !*done {
87//! done = cvar.wait(done).unwrap();
88//! }
89//! }
90//! }
91//!
92//! // Read the output
93//! job.output.get().unwrap().clone()
94//! }
95//!
96//! impl Input {
97//! fn process(&mut self) -> Output {
98//! // ...
99//! # Output
100//! }
101//! }
102//! # struct Input; #[derive(Clone)] struct Output;
103//! ```
104#![no_std]
105use core::{
106 cell::UnsafeCell,
107 mem::ManuallyDrop,
108 sync::atomic::{AtomicBool, Ordering},
109};
110
111/// A cell type which value can be taken only once.
112///
113/// See [crate-level documentation](mod@self) for more.
114#[derive(Default)]
115pub struct TakeCell<T: ?Sized> {
116 taken: AtomicBool,
117 value: UnsafeCell<T>,
118}
119
120impl<T> TakeCell<T> {
121 /// Creates a new `TakeCell` containing the given value.
122 pub const fn new(v: T) -> Self {
123 Self {
124 taken: AtomicBool::new(false),
125 value: UnsafeCell::new(v),
126 }
127 }
128
129 /// Unwraps the underlying value.
130 pub fn into_inner(self) -> T {
131 // TODO: make `into_inner` `const` when `UnsafeCell::into_inner` as `const fn`
132 // will be stabilized.
133 self.value.into_inner()
134 }
135}
136
137impl<T: ?Sized> TakeCell<T> {
138 /// Returns a reference to the underlying value.
139 ///
140 /// After this function once returns `Some(_)` all consequtive calls before
141 /// [`heal`] will return `None` as the reference is already taken.
142 ///
143 /// [`heal`]: TakeCell::heal
144 ///
145 /// ## Examples
146 ///
147 /// ```
148 /// # use takecell::TakeCell;
149 /// let cell = TakeCell::new(0);
150 ///
151 /// let uref: &mut _ = cell.take().unwrap();
152 /// *uref = 17;
153 ///
154 /// // Already taken
155 /// assert!(cell.take().is_none());
156 ///
157 /// let value = cell.into_inner();
158 /// assert_eq!(value, 17);
159 /// ```
160 pub fn take(&self) -> Option<&mut T> {
161 // ## Safety
162 //
163 // Aside from `steal` (that is unsafe and it's caller must guarantee that there
164 // are no concurent calls to `steal`/`take`) this is the only place where we are
165 // changing the value of `self.taken`.
166 //
167 // This is also the only place (again, aside from `steal`) where we use/provide
168 // a reference to the underlying value.
169 //
170 // Since this `swap` only changes the value from `false` to `true`, it can only
171 // return `false` once. This guarantees that the returned reference is
172 // unique.
173 //
174 // Two threads can't both swap false->true, this is guaranteed by the
175 // specification:
176 // > All modifications to any particular atomic variable
177 // > occur in a total order that is specific to this one atomic variable.
178 // > <https://en.cppreference.com/w/cpp/atomic/memory_order>
179 //
180 // `Relaxed` ordering is ok to use here, because when `TakeCell` is shared we
181 // only allow one (1) thread to access the protected memory, so there is no need
182 // to synchronize the memory between threads. When `TakeCell` is not shared and
183 // can be accessed with `get`, the thread that is holding `&mut TakeCell<_>`
184 // must have already synchronized itself with other threads so, again, there is
185 // no need for additional synchronization here. See also:
186 // <https://discord.com/channels/500028886025895936/628283088555737089/929435782370955344>.
187 match self.taken.swap(true, Ordering::Relaxed) {
188 // The cell was previously taken
189 true => None,
190 // The cell wasn't takes before, so we can take it
191 false => Some(unsafe { &mut *self.value.get() }),
192 }
193 }
194
195 /// Returns `true` if a reference to the underlying value has been already
196 /// [`take`]n.
197 ///
198 /// ie if this function returns `true`, then [`take`] will return `None`.
199 /// Note however that the oposite is not true: if this function returned
200 /// `false` it doesn't guarantee that [`take`] will return `Some(_)` since
201 /// there may have been concurent calls to [`take`].
202 ///
203 /// [`take`]: TakeCell::take
204 pub fn is_taken(&self) -> bool {
205 self.taken.load(Ordering::Relaxed)
206 }
207
208 /// Returns a unique reference to the underlying data.
209 ///
210 /// This call borrows `TakeCell` uniquely (at compile-time) which guarantees
211 /// that we possess the only reference.
212 ///
213 /// Note that this function is not affected nor affects the [`take`]. ie
214 /// this function will return a reference even if [`take`] was already
215 /// called
216 ///
217 /// [`take`]: TakeCell::take
218 pub fn get(&mut self) -> &mut T {
219 // TODO: make `get` `const` when `UnsafeCell::get_mut` as `const fn`
220 // will be stabilized.
221 self.value.get_mut()
222 }
223
224 /// Heal this cell. After a call to this function next call to [`take`] will
225 /// succeed again, even if [`take`] was called before.
226 ///
227 /// ## Examples
228 ///
229 /// ```
230 /// # use takecell::TakeCell;
231 /// let mut cell = TakeCell::new(0);
232 ///
233 /// assert!(cell.take().is_some());
234 /// assert!(cell.is_taken());
235 ///
236 /// cell.heal();
237 ///
238 /// assert!(!cell.is_taken());
239 /// assert!(cell.take().is_some());
240 /// ```
241 ///
242 /// [`take`]: TakeCell::take
243 pub fn heal(&mut self) {
244 // Unique reference to self guarantees that the reference retuened from
245 // `take`/`steal` (if these function were even called) is dead, thus it's okay
246 // to allow a new unique reference to the underlying value to be created.
247 self.taken = AtomicBool::new(false);
248 }
249
250 /// Similar to [`is_taken`], but uses unique reference instead of runtime
251 /// synchronization.
252 ///
253 /// [`is_taken`]: TakeCell::is_taken
254 pub fn is_taken_unsync(&mut self) -> bool {
255 *self.taken.get_mut()
256 }
257
258 /// Similar to [`take`], but uses unique reference instead of runtime
259 /// synchronization.
260 ///
261 /// [`take`]: TakeCell::take
262 pub fn take_unsync(&mut self) -> Option<&mut T> {
263 match self.is_taken_unsync() {
264 false => {
265 *self.taken.get_mut() = true;
266 Some(self.get())
267 }
268 true => None,
269 }
270 }
271
272 /// Unchecked version of [`take`].
273 ///
274 /// ## Safety
275 ///
276 /// Call to this function must be the first call to [`steal`] or [`take`]
277 /// after cell creation or [`heal`].
278 ///
279 /// [`take`]: TakeCell::take
280 /// [`steal`]: TakeCell::steal
281 /// [`heal`]: TakeCell::heal
282 #[allow(clippy::mut_from_ref)]
283 pub unsafe fn steal(&self) -> &mut T {
284 self.taken.store(true, Ordering::Relaxed);
285
286 // ## Safety
287 //
288 // Guaranteed by the caller
289 &mut *self.value.get()
290 }
291}
292
293impl<T> From<T> for TakeCell<T> {
294 fn from(v: T) -> Self {
295 Self::new(v)
296 }
297}
298
299/// ## Safety
300///
301/// It is possible to pass ownership via `&TakeCell`. As such, `TakeCell<T>` may
302/// be `Sync` (`TakeCell<T>: Send`) if and only if `T` is `Send`. Otherwise
303/// there may be UB, see [this example], adopted from sslab-gatech rust group.
304///
305/// [this example]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c5add45a552290fc206fe2e9c768e03f
306///
307/// `Sync` on the other hand is not required because `TakeCell`'s value is only
308/// accesible from one thread at a time.
309///
310/// This is again similar to a `Mutex`.
311unsafe impl<T: ?Sized + Send> Sync for TakeCell<T> {}
312
313/// A cell type which value can be taken only once.
314///
315/// In difference with [`TakeCell`](crate::TakeCell), this type provides
316/// ownership, and not a reference to the inner value. Because of this it can't
317/// contain unsized values.
318///
319/// See [crate-level documentation](mod@self) for more.
320#[derive(Default)]
321pub struct TakeOwnCell<T>(
322 // Invariant: `TakeCell::taken` is true <=> `ManuallyDrop`'s value was taken
323 TakeCell<ManuallyDrop<T>>,
324);
325
326impl<T> TakeOwnCell<T> {
327 /// Creates a new `TakeOwnCell` containing the given value.
328 pub const fn new(v: T) -> Self {
329 Self(TakeCell::new(ManuallyDrop::new(v)))
330 }
331
332 /// Returns the underlying value.
333 ///
334 /// After this function once returns `Some(_)` all consequtive calls before
335 /// [`heal`] will return `None` as the value is already taken.
336 ///
337 /// [`heal`]: TakeOwnCell::heal
338 ///
339 /// ## Examples
340 ///
341 /// ```
342 /// # use takecell::TakeOwnCell;
343 /// let cell = TakeOwnCell::new(17);
344 ///
345 /// let value: i32 = cell.take().unwrap();
346 /// assert_eq!(value, 17);
347 ///
348 /// // Already taken
349 /// assert!(cell.take().is_none());
350 /// assert!(cell.into_inner().is_none());
351 /// ```
352 pub fn take(&self) -> Option<T> {
353 self.0
354 .take()
355 // ## Safety
356 //
357 // `TakeCell` guatantees that unique reference to the underlying value is returned only
358 // once before `TakeCell::heal`. We ensure a new value is emplaced if it was taken
359 // before calling `TakeCell::heal`.
360 //
361 // In all other places (like `drop` and `get`) we check if the value was taken.
362 //
363 // This guarantees that the value is not duplicated.
364 .map(|value| unsafe { ManuallyDrop::take(value) })
365 }
366
367 /// Returns `true` if the underlying value has been already [`take`]n.
368 ///
369 /// ie if this function returns `true`, then [`take`] will return `None`.
370 /// Note however that the oposite is not true: if this function returned
371 /// `false` it doesn't guarantee that [`take`] will return `Some(_)` since
372 /// there may have been concurent calls to [`take`].
373 ///
374 /// [`take`]: TakeOwnCell::take
375 pub fn is_taken(&self) -> bool {
376 self.0.is_taken()
377 }
378
379 /// Returns a unique reference to the underlying data.
380 ///
381 /// This call borrows `TakeOwnCell` uniquely (at compile-time) which
382 /// guarantees that we possess the only reference.
383 ///
384 /// Note that this function does not affect the [`take`]. ie [`take`] may
385 /// still return `Some(_)` after a call to this function. The oposite is not
386 /// true, after the value is [`take`]n this function returns `None`.
387 ///
388 /// [`take`]: TakeOwnCell::take
389 pub fn get(&mut self) -> Option<&mut T> {
390 match self.is_taken() {
391 false => {
392 // ## Safety
393 //
394 // While this code doesn't use `unsafe{}` it can be affected by other unsafe
395 // blocks (see: `take`).
396 //
397 // The value may only be accessed if it was not taken before.
398 Some(&mut *self.0.get())
399 }
400 true => None,
401 }
402 }
403
404 /// Unwraps the underlying value.
405 pub fn into_inner(mut self) -> Option<T> {
406 self.take_unsync()
407 }
408
409 /// Heal this cell. After a call to this function next call to [`take`] will
410 /// succeed again, even if [`take`] was called before.
411 ///
412 /// Returns a reference to the underlying value and `Err(v)` if this cell
413 /// was not taken before the call to this function.
414 ///
415 /// ## Examples
416 ///
417 /// ```
418 /// # use takecell::TakeOwnCell;
419 /// let mut cell = TakeOwnCell::new(17);
420 ///
421 /// let (uref, res) = cell.heal(12);
422 /// assert_eq!(res, Err(12));
423 /// assert_eq!(*uref, 17);
424 /// *uref = 0xAA;
425 ///
426 /// assert_eq!(cell.take(), Some(0xAA));
427 ///
428 /// let (uref, res) = cell.heal(12);
429 /// assert!(res.is_ok());
430 /// assert_eq!(*uref, 12);
431 /// *uref = 0xBB;
432 ///
433 /// assert_eq!(cell.into_inner(), Some(0xBB));
434 /// ```
435 ///
436 /// [`take`]: TakeCell::take
437 pub fn heal(&mut self, v: T) -> (&mut T, Result<(), T>) {
438 // ## Safety
439 //
440 // While this code doesn't use `unsafe{}` it can be affected by other unsafe
441 // blocks (see: `take`).
442 //
443 // The value must be emplaced if it was previously taken, before healing the
444 // underlying cell.
445
446 let res = match self.0.is_taken() {
447 true => {
448 *self.0.get() = ManuallyDrop::new(v);
449 Ok(())
450 }
451 false => Err(v),
452 };
453
454 self.0.heal();
455
456 let uref = &mut *self.0.get();
457 (uref, res)
458 }
459
460 /// Similar to [`is_taken`], but uses unique reference instead of runtime
461 /// synchronization.
462 ///
463 /// [`is_taken`]: TakeOwnCell::is_taken
464 pub fn is_taken_unsync(&mut self) -> bool {
465 self.0.is_taken_unsync()
466 }
467
468 /// Similar to [`take`], but uses unique reference instead of runtime
469 /// synchronization.
470 ///
471 /// [`take`]: TakeOwnCell::take
472 pub fn take_unsync(&mut self) -> Option<T> {
473 self.0
474 .take_unsync()
475 // ## Safety
476 //
477 // `TakeCell` guatantees that unique reference to the underlying value is returned only
478 // once before `TakeCell::heal`. We ensure a new value is emplaced if it was taken
479 // before calling `TakeCell::heal`.
480 //
481 // In all other places (like `drop` and `get`) we check if the value was taken.
482 //
483 // This guarantees that the value is not duplicated.
484 .map(|value| unsafe { ManuallyDrop::take(value) })
485 }
486
487 /// Unchecked version of [`take`].
488 ///
489 /// ## Safety
490 ///
491 /// Call to this function must be the first call to [`steal`] or [`take`]
492 /// after cell creation or [`heal`].
493 ///
494 /// [`take`]: TakeOwnCell::take
495 /// [`steal`]: TakeOwnCell::steal
496 /// [`heal`]: TakeOwnCell::heal
497 pub unsafe fn steal(&self) -> T {
498 // ## Safety
499 //
500 // Guaranteed by the caller
501 ManuallyDrop::take(self.0.steal())
502 }
503}
504
505impl<T> From<T> for TakeOwnCell<T> {
506 fn from(v: T) -> Self {
507 Self::new(v)
508 }
509}
510
511/// ## Safety
512///
513/// It is possible to pass ownership via `&TakeOwnCell`. As such,
514/// `TakeOwnCell<T>` may be `Sync` (`TakeOwnCell<T>: Send`) if and only if `T`
515/// is `Send`. Otherwise there may be UB, see [this example], adopted from
516/// sslab-gatech rust group.
517///
518/// [this example]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c5add45a552290fc206fe2e9c768e03f
519///
520/// `Sync` on the other hand is not required because `TakeOwnCell`'s value is
521/// only accesible from one thread at a time.
522///
523/// This is again similar to a `Mutex`.
524unsafe impl<T: Send> Sync for TakeOwnCell<T> {}
525
526impl<T> Drop for TakeOwnCell<T> {
527 fn drop(&mut self) {
528 // Drop the underlying value, if the cell still holds it
529 let _ = self.take_unsync();
530 }
531}
532
533#[cfg(test)]
534mod tests {
535 use crate::TakeCell;
536
537 #[test]
538 fn it_works() {
539 let cell = TakeCell::new(0);
540
541 {
542 let uref = cell.take().unwrap();
543 *uref += 1;
544 assert_eq!(*uref, 1);
545
546 assert!(cell.take().is_none());
547
548 *uref += 1;
549 assert_eq!(*uref, 2);
550 }
551
552 assert!(cell.take().is_none());
553 assert_eq!(cell.into_inner(), 2);
554 }
555
556 #[test]
557 fn unsize() {
558 let cell: TakeCell<[i32; 10]> = TakeCell::new([0; 10]);
559
560 let _: &TakeCell<[i32]> = &cell;
561 let _: &TakeCell<dyn Send> = &cell;
562 }
563
564 #[test]
565 fn r#static() {
566 static CELL: TakeCell<i32> = TakeCell::new(0);
567
568 {
569 let uref: &'static mut i32 = CELL.take().unwrap();
570 *uref += 1;
571 assert_eq!(*uref, 1);
572
573 assert!(CELL.take().is_none());
574
575 *uref += 1;
576 assert_eq!(*uref, 2);
577 }
578
579 assert!(CELL.take().is_none());
580 }
581
582 #[test]
583 fn steal_takes() {
584 let cell = TakeCell::new(0);
585
586 // ## Safety
587 //
588 // There was no calls to take or steal before
589 let uref = unsafe { cell.steal() };
590 *uref += 1;
591 assert_eq!(*uref, 1);
592
593 assert!(cell.is_taken());
594 assert!(cell.take().is_none());
595
596 *uref += 1;
597 assert_eq!(*uref, 2);
598 assert_eq!(cell.into_inner(), 2);
599 }
600}
601
602#[cfg(test)]
603mod own_tests {
604 use crate::TakeOwnCell;
605
606 #[test]
607 fn it_works() {
608 let cell = TakeOwnCell::new(17);
609
610 assert_eq!(cell.take(), Some(17));
611
612 assert!(cell.take().is_none());
613 assert!(cell.into_inner().is_none());
614 }
615
616 #[test]
617 fn heal() {
618 let mut cell = TakeOwnCell::new(17);
619
620 let (uref, res) = cell.heal(12);
621 assert_eq!(res, Err(12));
622 assert_eq!(*uref, 17);
623 *uref = 0xAA;
624
625 assert_eq!(cell.take(), Some(0xAA));
626
627 let (uref, res) = cell.heal(12);
628 assert!(res.is_ok());
629 assert_eq!(*uref, 12);
630 *uref = 0xBB;
631
632 assert_eq!(cell.into_inner(), Some(0xBB));
633 }
634
635 #[test]
636 fn r#static() {
637 static CELL: TakeOwnCell<i32> = TakeOwnCell::new(42);
638
639 assert!(!CELL.is_taken());
640
641 assert_eq!(CELL.take(), Some(42));
642
643 assert!(CELL.is_taken());
644 assert!(CELL.take().is_none());
645 }
646
647 #[test]
648 fn steal_takes() {
649 let cell = TakeOwnCell::new(1);
650
651 assert!(!cell.is_taken());
652
653 // ## Safety
654 //
655 // There was no calls to take or steal before
656 assert_eq!(unsafe { cell.steal() }, 1);
657
658 assert!(cell.is_taken());
659 assert!(cell.take().is_none());
660 assert!(cell.into_inner().is_none());
661 }
662}