1#![no_std]
2use core::cell::UnsafeCell;
3use core::sync::atomic::Ordering::{Acquire, Release};
4use core::sync::atomic::{spin_loop_hint, AtomicBool};
5
6#[derive(Debug)]
8pub struct PingPongCell<T> {
9 is_working: AtomicBool,
10 value: UnsafeCell<Option<T>>,
11}
12
13unsafe impl<T: Send> Send for PingPongCell<T> {}
14unsafe impl<T: Sync> Sync for PingPongCell<T> {}
15
16impl<T> PingPongCell<T> {
17 pub fn new(value: Option<T>) -> Self {
19 PingPongCell {
20 is_working: AtomicBool::new(false),
21 value: UnsafeCell::new(value),
22 }
23 }
24
25 #[inline]
27 pub fn take(&self) -> Option<T> {
28 self.transact(|state| state.take())
29 }
30
31 #[inline]
33 pub fn put(&self, value: T) {
34 self.transact(|state| *state = Some(value));
35 }
36
37 pub fn put_if_empty(&self, value: T) -> Result<(), T> {
39 self.transact(|state| {
40 if state.is_some() {
41 Err(value)
42 } else {
43 *state = Some(value);
44 Ok(())
45 }
46 })
47 }
48
49 pub fn transact<F, R>(&self, fun: F) -> R
51 where
52 F: FnOnce(&mut Option<T>) -> R,
53 {
54 while self.is_working.compare_and_swap(false, true, Acquire) {
55 spin_loop_hint();
56 }
57 let ret = unsafe { fun(&mut *self.value.get()) };
58 self.is_working.store(false, Release);
59 ret
60 }
61}
62
63impl<T: Clone> PingPongCell<T> {
64 pub fn put_empty_clone(&self, value: T) -> Result<(), (T, T)> {
66 self.transact(|state| {
67 if let Some(ref old) = state {
68 Err((value, old.clone()))
69 } else {
70 *state = Some(value);
71 Ok(())
72 }
73 })
74 }
75
76 pub fn clone_inner(&self) -> Option<T> {
78 self.transact(|state| state.clone())
79 }
80}
81
82impl<T: Eq> PingPongCell<T> {
83 pub fn compare_and_swap(&self, expected: &T, new: T) -> Result<(), T> {
85 self.transact(|state| match state {
86 Some(ref mut val) if val == expected => {
87 *val = new;
88 Ok(())
89 }
90 _ => Err(new),
91 })
92 }
93}
94
95impl<T: Clone + Eq> PingPongCell<T> {
96 pub fn compare_swap_clone(&self, expected: &T, new: T) -> Result<(), (T, Option<T>)> {
98 self.transact(|state| match state {
99 Some(val) if val == expected => {
100 *state = Some(new);
101 Ok(())
102 }
103 Some(val) => Err((new, Some(val.clone()))),
104 None => Err((new, None)),
105 })
106 }
107}