1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use std::cell::UnsafeCell;
use std::mem::MaybeUninit;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use crate::{PopError, PushError};
const LOCKED: usize = 1 << 0;
const PUSHED: usize = 1 << 1;
const CLOSED: usize = 1 << 2;
pub struct Single<T> {
state: AtomicUsize,
slot: UnsafeCell<MaybeUninit<T>>,
}
impl<T> Single<T> {
pub fn new() -> Single<T> {
Single {
state: AtomicUsize::new(0),
slot: UnsafeCell::new(MaybeUninit::uninit()),
}
}
pub fn push(&self, value: T) -> Result<(), PushError<T>> {
let state = self
.state
.compare_and_swap(0, LOCKED | PUSHED, Ordering::SeqCst);
if state == 0 {
unsafe { self.slot.get().write(MaybeUninit::new(value)) }
self.state.fetch_and(!LOCKED, Ordering::Release);
Ok(())
} else if state & CLOSED != 0 {
Err(PushError::Closed(value))
} else {
Err(PushError::Full(value))
}
}
pub fn pop(&self) -> Result<T, PopError> {
let mut state = PUSHED;
loop {
let prev =
self.state
.compare_and_swap(state, (state | LOCKED) & !PUSHED, Ordering::SeqCst);
if prev == state {
let value = unsafe { self.slot.get().read().assume_init() };
self.state.fetch_and(!LOCKED, Ordering::Release);
return Ok(value);
}
if prev & PUSHED == 0 {
if prev & CLOSED == 0 {
return Err(PopError::Empty);
} else {
return Err(PopError::Closed);
}
}
if prev & LOCKED == 0 {
state = prev;
} else {
thread::yield_now();
state = prev & !LOCKED;
}
}
}
pub fn len(&self) -> usize {
if self.state.load(Ordering::SeqCst) & PUSHED == 0 {
0
} else {
1
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn is_full(&self) -> bool {
self.len() == 1
}
pub fn close(&self) -> bool {
let state = self.state.fetch_or(CLOSED, Ordering::SeqCst);
state & CLOSED == 0
}
pub fn is_closed(&self) -> bool {
self.state.load(Ordering::SeqCst) & CLOSED != 0
}
}
impl<T> Drop for Single<T> {
fn drop(&mut self) {
if *self.state.get_mut() & PUSHED != 0 {
let value = unsafe { self.slot.get().read().assume_init() };
drop(value);
}
}
}