1use core::{
7 cell::Cell,
8 cmp,
9 hash::{Hash, Hasher},
10 num,
11 sync::atomic::{Ordering::*, *},
12};
13
14use radium::Radium;
15
16macro_rules! inc {
17 (fn inc($self:ident) -> Option<Self> { $($block:tt)* }) => {
18 #[doc(hidden)]
19 const LOCAL_INIT: Self::Local = Self::Local::new(0);
20 #[doc(hidden)]
21 const ATOMIC_INIT: Self::Atomic = Self::Atomic::new(0);
22
23 #[inline]
24 #[doc(hidden)]
25 fn inc_local($self: &Self::Local) -> Option<Self> { $($block)* }
26 #[doc(hidden)]
27 fn inc_atomic($self: &Self::Atomic) -> Option<Self> { $($block)* }
28 };
29}
30
31pub trait Scalar: crate::Seal + Copy + Ord + Hash {
41 #[doc(hidden)]
42 type Local;
43 #[doc(hidden)]
44 type Atomic;
45
46 #[doc(hidden)]
47 const LOCAL_INIT: Self::Local;
48 #[doc(hidden)]
49 const ATOMIC_INIT: Self::Atomic;
50
51 #[doc(hidden)]
52 fn inc_local(local: &Self::Local) -> Option<Self>;
53 #[doc(hidden)]
54 fn inc_atomic(local: &Self::Atomic) -> Option<Self>;
55}
56
57pub struct OpaqueScalar<S: ScalarAllocator>(S::Scalar);
60
61impl<S: ScalarAllocator> OpaqueScalar<S> {
62 pub unsafe fn new(scalar: S::Scalar) -> Self { Self(scalar) }
69
70 pub fn into_inner(self) -> S::Scalar { self.0 }
72}
73
74pub unsafe trait ScalarAllocator {
83 type Scalar: Clone + Eq;
85 type AutoTraits;
88
89 fn alloc() -> Self::Scalar;
95}
96
97impl<A: ScalarAllocator> Eq for OpaqueScalar<A> {}
98impl<A: ScalarAllocator> PartialEq for OpaqueScalar<A> {
99 fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
100}
101
102impl<A: ScalarAllocator> Hash for OpaqueScalar<A>
103where
104 A::Scalar: Hash,
105{
106 fn hash<H: Hasher>(&self, state: &mut H) { self.0.hash(state) }
107}
108
109impl<A: ScalarAllocator> PartialOrd for OpaqueScalar<A>
110where
111 A::Scalar: PartialOrd,
112{
113 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { self.0.partial_cmp(&other.0) }
114}
115
116impl<A: ScalarAllocator> Ord for OpaqueScalar<A>
117where
118 A::Scalar: Ord,
119{
120 fn cmp(&self, other: &Self) -> cmp::Ordering { self.0.cmp(&other.0) }
121}
122
123impl crate::Seal for () {}
124impl Scalar for () {
125 #[doc(hidden)]
126 type Local = Cell<bool>;
127 #[doc(hidden)]
128 type Atomic = AtomicBool;
129
130 #[doc(hidden)]
131 const LOCAL_INIT: Self::Local = Cell::new(false);
132 #[doc(hidden)]
133 const ATOMIC_INIT: Self::Atomic = AtomicBool::new(false);
134
135 #[doc(hidden)]
136 #[inline]
137 fn inc_local(local: &Self::Local) -> Option<Self> {
138 match local.replace(true) {
139 false => Some(()),
140 true => None,
141 }
142 }
143
144 #[doc(hidden)]
145 #[inline]
146 fn inc_atomic(local: &Self::Atomic) -> Option<Self> {
147 match local.swap(true, Relaxed) {
148 false => Some(()),
149 true => None,
150 }
151 }
152}
153
154#[doc(hidden)]
155#[macro_export]
156macro_rules! __scalar_allocator {
157 (@create $name:ident) => {
158 impl $name {
159 pub fn oneshot() -> $crate::dynamic::Dynamic<Self> { $crate::dynamic::Dynamic::with_alloc() }
161
162 pub fn with_pool<P: $crate::pool::PoolMut<Self>>(pool: P) -> $crate::dynamic::Dynamic<Self, P> {
164 $crate::dynamic::Dynamic::with_alloc_and_pool(pool)
165 }
166 }
167 };
168 (@create type $name:ident) => {
169 impl $name {
170 pub fn oneshot() -> $crate::dynamic::Dynamic<Self> { $crate::dynamic::Dynamic::with_alloc() }
172
173 pub fn reuse() -> $crate::dynamic::Dynamic<Self, Self> { Self::with_pool(Self) }
175
176 pub fn with_pool<P: $crate::pool::PoolMut<Self>>(pool: P) -> $crate::dynamic::Dynamic<Self, P> {
178 $crate::dynamic::Dynamic::with_alloc_and_pool(pool)
179 }
180 }
181 };
182 (
183 $(#[$meta:meta])*
184 $v:vis struct $name:ident($scalar:ty);
185 ) => {
186 $(#[$meta])*
187 $v struct $name;
188
189 unsafe impl $crate::scalar::ScalarAllocator for $name {
190 type Scalar = $scalar;
191 type AutoTraits = ();
192
193 fn alloc() -> Self::Scalar {
194 static __SCALAR_ALLOCATOR: <$scalar as $crate::scalar::Scalar>::Atomic = <$scalar as $crate::scalar::Scalar>::ATOMIC_INIT;
195
196 $crate::scalar::Scalar::inc_atomic(&__SCALAR_ALLOCATOR)
197 .expect(concat!(
198 "Could not allocate more scalars from ",
199 stringify!($name),
200 ))
201 }
202 }
203 };
204 (
205 $(#[$meta:meta])*
206 $v:vis thread_local struct $name:ident($scalar:ty);
207 ) => {
208 $(#[$meta])*
209 $v struct $name;
210
211 unsafe impl $crate::scalar::ScalarAllocator for $name {
212 type Scalar = $scalar;
213 type AutoTraits = $crate::export::NoSendSync;
214
215 fn alloc() -> Self::Scalar {
216 $crate::export::thread_local! {
217 static __SCALAR_ALLOCATOR: <$scalar as $crate::scalar::Scalar>::Local = <$scalar as $crate::scalar::Scalar>::LOCAL_INIT;
218 }
219
220 __SCALAR_ALLOCATOR.with(|scalar| {
221 $crate::scalar::Scalar::inc_local(scalar)
222 }).expect(concat!(
223 "Could not allocate more scalars from ",
224 stringify!($name),
225 ))
226 }
227 }
228 };
229}
230
231#[macro_export]
283macro_rules! scalar_allocator {
284 (
285 $(#[$meta:meta])*
286 $v:vis struct $name:ident;
287 ) => {
288 $crate::__scalar_allocator! {
289 $(#[$meta])*
290 $v struct $name(());
291 }
292
293 $crate::__scalar_allocator! {
294 @create type $name
295 }
296
297 $crate::__global_pool! {
298 $name($crate::pool::Flag<$name>)
299 }
300 };
301 (
302 $(#[$meta:meta])*
303 $v:vis thread_local struct $name:ident;
304 ) => {
305 $crate::__scalar_allocator! {
306 $(#[$meta])*
307 $v thread_local struct $name(());
308 }
309
310 $crate::__scalar_allocator! {
311 @create type $name
312 }
313
314 $crate::__global_pool! {
315 thread_local $name($crate::export::LocalFlag<$name>)
316 }
317 };
318 (
319 $(#[$meta:meta])*
320 $v:vis struct $name:ident($scalar:ty);
321 ) => {
322 $crate::__scalar_allocator! {
323 $(#[$meta])*
324 $v struct $name($scalar);
325 }
326
327 $crate::__scalar_allocator! {
328 @create $name
329 }
330 };
331 (
332 $(#[$meta:meta])*
333 $v:vis thread_local struct $name:ident($scalar:ty);
334 ) => {
335 $crate::__scalar_allocator! {
336 $(#[$meta])*
337 $v thread_local struct $name($scalar);
338 }
339
340 $crate::__scalar_allocator! {
341 @create $name
342 }
343 };
344}
345
346macro_rules! norm_prim {
347 ($($prim:ty => $atomic:ty, $nonzero:ty,)*) => {$(
348 impl crate::Seal for $prim {}
349 impl Scalar for $prim {
350 #[doc(hidden)]
351 type Local = Cell<$prim>;
352 #[doc(hidden)]
353 type Atomic = $atomic;
354
355 inc! {
356 fn inc(this) -> Option<Self> {
357 let mut value = this.load(Relaxed);
358
359 loop {
360 let next = value.checked_add(1)?;
361
362 if let Err(current) = this.compare_exchange_weak(value, next, Acquire, Relaxed) {
363 value = current
364 } else {
365 return Some(value)
366 }
367 }
368 }
369 }
370 }
371
372 impl crate::Seal for $nonzero {}
373 impl Scalar for $nonzero {
374 #[doc(hidden)]
375 type Local = Cell<$prim>;
376 #[doc(hidden)]
377 type Atomic = $atomic;
378
379 inc! {
380 fn inc(this) -> Option<Self> {
381 let mut value = this.load(Relaxed);
382
383 loop {
384 let next = value.checked_add(1)?;
385
386 if let Err(current) = this.compare_exchange_weak(value, next, Acquire, Relaxed) {
387 value = current
388 } else {
389 return <$nonzero>::new(value.wrapping_add(1))
390 }
391 }
392 }
393 }
394 }
395 )*};
396}
397
398norm_prim! {
399 u8 => AtomicU8, num::NonZeroU8,
400 u16 => AtomicU16, num::NonZeroU16,
401 u32 => AtomicU32, num::NonZeroU32,
402 u64 => AtomicU64, num::NonZeroU64,
403 usize => AtomicUsize, num::NonZeroUsize,
404}