1use crate::{NullTag, Shared, Shield, Tag};
2use core::{
3 fmt,
4 marker::PhantomData,
5 mem,
6 sync::atomic::{AtomicUsize, Ordering},
7};
8
9fn map_both<T, U, F>(result: Result<T, T>, f: F) -> Result<U, U>
10where
11 F: FnOnce(T) -> U + Copy,
12{
13 result.map(f).map_err(f)
14}
15
16#[repr(transparent)]
21pub struct Atomic<V, T1 = NullTag, T2 = NullTag>
22where
23 T1: Tag,
24 T2: Tag,
25{
26 pub(crate) data: AtomicUsize,
27 _m0: PhantomData<V>,
28 _m1: PhantomData<T1>,
29 _m2: PhantomData<T2>,
30}
31
32impl<V, T1, T2> Atomic<V, T1, T2>
33where
34 T1: Tag,
35 T2: Tag,
36{
37 pub unsafe fn from_raw(raw: usize) -> Self {
43 Self {
44 data: AtomicUsize::new(raw),
45 _m0: PhantomData,
46 _m1: PhantomData,
47 _m2: PhantomData,
48 }
49 }
50
51 pub fn new(shared: Shared<'_, V, T1, T2>) -> Self {
56 unsafe { Self::from_raw(shared.into_raw()) }
57 }
58
59 pub fn null() -> Self {
61 unsafe { Self::from_raw(0) }
62 }
63
64 pub fn null_vec(len: usize) -> Vec<Self> {
66 unsafe { mem::transmute(vec![0_usize; len]) }
67 }
68
69 pub fn load<'collector, 'shield, S>(
71 &self,
72 ordering: Ordering,
73 _shield: &'shield S,
74 ) -> Shared<'shield, V, T1, T2>
75 where
76 S: Shield<'collector>,
77 {
78 let raw = self.data.load(ordering);
79 unsafe { Shared::from_raw(raw) }
80 }
81
82 pub fn store(&self, data: Shared<'_, V, T1, T2>, ordering: Ordering) {
84 let raw = data.into_raw();
85 self.data.store(raw, ordering);
86 }
87
88 pub fn swap<'collector, 'shield, S>(
90 &self,
91 new: Shared<'_, V, T1, T2>,
92 ordering: Ordering,
93 _shield: &'shield S,
94 ) -> Shared<'shield, V, T1, T2>
95 where
96 S: Shield<'collector>,
97 {
98 let new_raw = new.into_raw();
99 let old_raw = self.data.swap(new_raw, ordering);
100 unsafe { Shared::from_raw(old_raw) }
101 }
102
103 pub fn compare_and_swap<'collector, 'shield, S>(
105 &self,
106 current: Shared<'_, V, T1, T2>,
107 new: Shared<'_, V, T1, T2>,
108 order: Ordering,
109 _shield: &'shield S,
110 ) -> Shared<'shield, V, T1, T2>
111 where
112 S: Shield<'collector>,
113 {
114 let current_raw = current.into_raw();
115 let new_raw = new.into_raw();
116 let old_raw = self.data.compare_and_swap(current_raw, new_raw, order);
117 unsafe { Shared::from_raw(old_raw) }
118 }
119
120 pub fn compare_exchange<'collector, 'shield, S>(
124 &self,
125 current: Shared<'_, V, T1, T2>,
126 new: Shared<'_, V, T1, T2>,
127 success: Ordering,
128 failure: Ordering,
129 _shield: &'shield S,
130 ) -> Result<Shared<'shield, V, T1, T2>, Shared<'shield, V, T1, T2>>
131 where
132 S: Shield<'collector>,
133 {
134 let current_raw = current.into_raw();
135 let new_raw = new.into_raw();
136 let result = self
137 .data
138 .compare_exchange(current_raw, new_raw, success, failure);
139
140 map_both(result, |raw| unsafe { Shared::from_raw(raw) })
141 }
142
143 pub fn compare_exchange_weak<'collector, 'shield, S>(
150 &self,
151 current: Shared<'_, V, T1, T2>,
152 new: Shared<'_, V, T1, T2>,
153 success: Ordering,
154 failure: Ordering,
155 _shield: &'shield S,
156 ) -> Result<Shared<'shield, V, T1, T2>, Shared<'shield, V, T1, T2>>
157 where
158 S: Shield<'collector>,
159 {
160 let current_raw = current.into_raw();
161 let new_raw = new.into_raw();
162 let result = self
163 .data
164 .compare_exchange_weak(current_raw, new_raw, success, failure);
165
166 map_both(result, |raw| unsafe { Shared::from_raw(raw) })
167 }
168}
169
170unsafe impl<V, T1, T2> Send for Atomic<V, T1, T2>
171where
172 T1: Tag,
173 T2: Tag,
174{
175}
176
177unsafe impl<V, T1, T2> Sync for Atomic<V, T1, T2>
178where
179 T1: Tag,
180 T2: Tag,
181{
182}
183
184impl<V, T1, T2> Unpin for Atomic<V, T1, T2>
185where
186 T1: Tag,
187 T2: Tag,
188{
189}
190
191impl<V, T1, T2> fmt::Debug for Atomic<V, T1, T2>
192where
193 T1: Tag,
194 T2: Tag,
195{
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 use crate::tag;
198 let data = self.data.load(Ordering::SeqCst);
199 let lo = tag::read_tag::<T1>(data, tag::TagPosition::Lo);
200 let hi = tag::read_tag::<T2>(data, tag::TagPosition::Hi);
201
202 f.debug_struct("Atomic")
203 .field("raw", &data)
204 .field("low_tag", &lo)
205 .field("high_tag", &hi)
206 .finish()
207 }
208}