1 //! `radium` provides a series of helper traits providing a uniform API for 2 //! interacting with both atomic types like 3 //! [`AtomicUsize`], and non-atomic types like [`Cell<T>`]. 4 //! 5 //! This crate is `#![no_std]`-compatible, and uses no non-core types. 6 //! 7 //! For details, see the documentation for [`Radium`]. 8 //! 9 //! Additionally, `radium` exports type aliases that map to the atomic types in 10 //! `core::sync::atomic` when they exist, and fall back to `Cell` wrappers when 11 //! the atomic is missing. These are accessible through the `types` module; you 12 //! can use these names for a guaranteed-portable symbol with best-effort atomic 13 //! behavior. 14 //! 15 //! --- 16 //! 17 //! **@kneecaw** - <https://twitter.com/kneecaw/status/1132695060812849154> 18 //! > Feelin' lazy: Has someone already written a helper trait abstracting 19 //! > operations over `AtomicUsize` and `Cell<usize>` for generic code which may 20 //! > not care about atomicity? 21 //! 22 //! **@ManishEarth** - <https://twitter.com/ManishEarth/status/1132706585300496384> 23 //! > no but call the crate radium 24 //! > 25 //! > (since people didn't care that it was radioactive and used it in everything) 26 //! 27 //! [`AtomicUsize`]: core::sync::atomic::AtomicUsize 28 //! [`Cell<T>`]: core::cell::Cell 29 30 #![no_std] 31 #![deny(unconditional_recursion)] 32 33 pub mod types; 34 35 use core::cell::Cell; 36 use core::sync::atomic::Ordering; 37 38 #[cfg(radium_atomic_8)] 39 use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU8}; 40 41 #[cfg(radium_atomic_16)] 42 use core::sync::atomic::{AtomicI16, AtomicU16}; 43 44 #[cfg(radium_atomic_32)] 45 use core::sync::atomic::{AtomicI32, AtomicU32}; 46 47 #[cfg(radium_atomic_64)] 48 use core::sync::atomic::{AtomicI64, AtomicU64}; 49 50 #[cfg(radium_atomic_ptr)] 51 use core::sync::atomic::{AtomicIsize, AtomicPtr, AtomicUsize}; 52 53 /// A maybe-atomic shared mutable fundamental type `T`. 54 /// 55 /// This trait is implemented by both the [atomic wrapper] type for `T`, and by 56 /// [`Cell<T>`], providing a consistent interface for interacting with the two 57 /// types. 58 /// 59 /// This trait provides methods predicated on marker traits for the underlying 60 /// fundamental. Only types which can be viewed as sequences of bits may use the 61 /// functions for bit-wise arithmetic, and only types which can be used as 62 /// integers may use the functions for numeric arithmetic. Use of these methods 63 /// on insufficient underlying types (for example, `Radium::fetch_and` on an 64 /// atomic or cell-wrapped pointer) will cause a compiler error. 65 /// 66 /// [atomic wrapper]: core::sync::atomic 67 /// [`Cell<T>`]: core::cell::Cell 68 pub trait Radium { 69 type Item; 70 /// Creates a new value of this type. new(value: Self::Item) -> Self71 fn new(value: Self::Item) -> Self; 72 73 /// If the underlying value is atomic, calls [`fence`] with the given 74 /// [`Ordering`]. Otherwise, does nothing. 75 /// 76 /// [`Ordering`]: core::sync::atomic::Ordering 77 /// [`fence`]: core::sync::atomic::fence fence(order: Ordering)78 fn fence(order: Ordering); 79 80 /// Returns a mutable reference to the underlying value. 81 /// 82 /// This is safe because the mutable reference to `self` guarantees that no 83 /// other references exist to this value. get_mut(&mut self) -> &mut Self::Item84 fn get_mut(&mut self) -> &mut Self::Item; 85 86 /// Consumes the wrapper and returns the contained value. 87 /// 88 /// This is safe as passing by value ensures no other references exist. into_inner(self) -> Self::Item89 fn into_inner(self) -> Self::Item; 90 91 /// Load a value from this object. 92 /// 93 /// Ordering values are ignored by non-atomic types. 94 /// 95 /// See also: [`AtomicUsize::load`]. 96 /// 97 /// [`AtomicUsize::load`]: core::sync::atomic::AtomicUsize::load load(&self, order: Ordering) -> Self::Item98 fn load(&self, order: Ordering) -> Self::Item; 99 100 /// Store a value in this object. 101 /// 102 /// Ordering arguments are ignored by non-atomic types. 103 /// 104 /// See also: [`AtomicUsize::store`]. 105 /// 106 /// [`AtomicUsize::store`]: core::sync::atomic::AtomicUsize::store store(&self, value: Self::Item, order: Ordering)107 fn store(&self, value: Self::Item, order: Ordering); 108 109 /// Swap with the value stored in this object. 110 /// 111 /// Ordering arguments are ignored by non-atomic types. 112 /// 113 /// See also: [`AtomicUsize::swap`]. 114 /// 115 /// [`AtomicUsize::swap`]: core::sync::atomic::AtomicUsize::swap swap(&self, value: Self::Item, order: Ordering) -> Self::Item116 fn swap(&self, value: Self::Item, order: Ordering) -> Self::Item; 117 118 /// Stores a value into this object if the currently-stored value is the 119 /// same as the `current` value. 120 /// 121 /// The return value is always the previously-stored value. If it is equal to 122 /// `current`, then the value was updated with `new`. 123 /// 124 /// Ordering arguments are ignored by non-atomic types. 125 /// 126 /// See also: [`AtomicUsize::compare_and_swap`]. 127 /// 128 /// [`AtomicUsize::compare_and_swap`]: core::sync::atomic::AtomicUsize::compare_and_swap compare_and_swap(&self, current: Self::Item, new: Self::Item, order: Ordering) -> Self::Item129 fn compare_and_swap(&self, current: Self::Item, new: Self::Item, order: Ordering) 130 -> Self::Item; 131 132 /// Stores a value into this object if the currently-stored value is the 133 /// same as the `current` value. 134 /// 135 /// The return value is a `Result` indicating whether the new value was 136 /// written, and containing the previously-stored value. On success, this 137 /// value is guaranteed to be equal to `current`. 138 /// 139 /// Ordering arguments are ignored by non-atomic types. 140 /// 141 /// See also: [`AtomicUsize::compare_exchange`]. 142 /// 143 /// [`AtomicUsize::compare_exchange`]: core::sync::atomic::AtomicUsize::compare_exchange compare_exchange( &self, current: Self::Item, new: Self::Item, success: Ordering, failure: Ordering, ) -> Result<Self::Item, Self::Item>144 fn compare_exchange( 145 &self, 146 current: Self::Item, 147 new: Self::Item, 148 success: Ordering, 149 failure: Ordering, 150 ) -> Result<Self::Item, Self::Item>; 151 152 /// Stores a value into this object if the currently-stored value is the 153 /// same as the `current` value. 154 /// 155 /// Unlike `compare_exchange`, this function is allowed to spuriously fail 156 /// even when the comparison succeeds, which can result in more efficient 157 /// code on some platforms. The return value is a `Result` indicating 158 /// whether the new value was written, and containing the previously-stored 159 /// value. 160 /// 161 /// Ordering arguments are ignored by non-atomic types. 162 /// 163 /// See also: [`AtomicUsize::compare_exchange_weak`]. 164 /// 165 /// [`AtomicUsize::compare_exchange_weak`]: core::sync::atomic::AtomicUsize::compare_exchange_weak compare_exchange_weak( &self, current: Self::Item, new: Self::Item, success: Ordering, failure: Ordering, ) -> Result<Self::Item, Self::Item>166 fn compare_exchange_weak( 167 &self, 168 current: Self::Item, 169 new: Self::Item, 170 success: Ordering, 171 failure: Ordering, 172 ) -> Result<Self::Item, Self::Item>; 173 174 /// Performs a bitwise "and" on the currently-stored value and the argument 175 /// `value`, and stores the result in `self`. 176 /// 177 /// Returns the previously-stored value. 178 /// 179 /// Ordering arguments are ignored by non-atomic types. 180 /// 181 /// See also: [`AtomicUsize::fetch_and`]. 182 /// 183 /// [`AtomicUsize::fetch_and`]: core::sync::atomic::AtomicUsize::fetch_and fetch_and(&self, value: Self::Item, order: Ordering) -> Self::Item where Self::Item: marker::BitOps184 fn fetch_and(&self, value: Self::Item, order: Ordering) -> Self::Item 185 where 186 Self::Item: marker::BitOps; 187 188 /// Performs a bitwise "nand" on the currently-stored value and the argument 189 /// `value`, and stores the result in `self`. 190 /// 191 /// Returns the previously-stored value. 192 /// 193 /// Ordering arguments are ignored by non-atomic types. 194 /// 195 /// See also: [`AtomicUsize::fetch_nand`]. 196 /// 197 /// [`AtomicUsize::fetch_nand`]: core::sync::atomic::AtomicUsize::fetch_nand fetch_nand(&self, value: Self::Item, order: Ordering) -> Self::Item where Self::Item: marker::BitOps198 fn fetch_nand(&self, value: Self::Item, order: Ordering) -> Self::Item 199 where 200 Self::Item: marker::BitOps; 201 202 /// Performs a bitwise "or" on the currently-stored value and the argument 203 /// `value`, and stores the result in `self`. 204 /// 205 /// Returns the previously-stored value. 206 /// 207 /// Ordering arguments are ignored by non-atomic types. 208 /// 209 /// See also: [`AtomicUsize::fetch_or`]. 210 /// 211 /// [`AtomicUsize::fetch_or`]: core::sync::atomic::AtomicUsize::fetch_or fetch_or(&self, value: Self::Item, order: Ordering) -> Self::Item where Self::Item: marker::BitOps212 fn fetch_or(&self, value: Self::Item, order: Ordering) -> Self::Item 213 where 214 Self::Item: marker::BitOps; 215 216 /// Performs a bitwise "xor" on the currently-stored value and the argument 217 /// `value`, and stores the result in `self`. 218 /// 219 /// Returns the previously-stored value. 220 /// 221 /// Ordering arguments are ignored by non-atomic types. 222 /// 223 /// See also: [`AtomicUsize::fetch_xor`]. 224 /// 225 /// [`AtomicUsize::fetch_xor`]: core::sync::atomic::AtomicUsize::fetch_xor fetch_xor(&self, value: Self::Item, order: Ordering) -> Self::Item where Self::Item: marker::BitOps226 fn fetch_xor(&self, value: Self::Item, order: Ordering) -> Self::Item 227 where 228 Self::Item: marker::BitOps; 229 230 /// Adds `value` to the currently-stored value, wrapping on overflow, and 231 /// stores the result in `self`. 232 /// 233 /// Returns the previously-stored value. 234 /// 235 /// Ordering arguments are ignored by non-atomic types. 236 /// 237 /// See also: [`AtomicUsize::fetch_add`]. 238 /// 239 /// [`AtomicUsize::fetch_add`]: core::sync::atomic::AtomicUsize::fetch_add fetch_add(&self, value: Self::Item, order: Ordering) -> Self::Item where Self::Item: marker::NumericOps240 fn fetch_add(&self, value: Self::Item, order: Ordering) -> Self::Item 241 where 242 Self::Item: marker::NumericOps; 243 244 /// Subtracts `value` from the currently-stored value, wrapping on 245 /// underflow, and stores the result in `self`. 246 /// 247 /// Returns the previously-stored value. 248 /// 249 /// Ordering arguments are ignored by non-atomic types. 250 /// 251 /// See also: [`AtomicUsize::fetch_sub`]. 252 /// 253 /// [`AtomicUsize::fetch_sub`]: core::sync::atomic::AtomicUsize::fetch_sub fetch_sub(&self, value: Self::Item, order: Ordering) -> Self::Item where Self::Item: marker::NumericOps254 fn fetch_sub(&self, value: Self::Item, order: Ordering) -> Self::Item 255 where 256 Self::Item: marker::NumericOps; 257 } 258 259 /// Marker traits used by [`Radium`]. 260 pub mod marker { 261 /// Types supporting maybe-atomic bitwise operations. 262 /// 263 /// Types implementing this trait support the [`fetch_and`], [`fetch_nand`], 264 /// [`fetch_or`], and [`fetch_xor`] maybe-atomic operations. 265 /// 266 /// [`fetch_and`]: crate::Radium::fetch_and 267 /// [`fetch_nand`]: crate::Radium::fetch_nand 268 /// [`fetch_or`]: crate::Radium::fetch_or 269 /// [`fetch_xor`]: crate::Radium::fetch_xor 270 /// 271 /// `bool` and all integer fundamental types implement this. 272 /// 273 /// ```rust 274 /// # use core::sync::atomic::*; 275 /// # use radium::Radium; 276 /// let num: AtomicUsize = AtomicUsize::new(0); 277 /// Radium::fetch_or(&num, 2, Ordering::Relaxed); 278 /// ``` 279 /// 280 /// Pointers do not. This will cause a compiler error. 281 /// 282 /// ```rust,compile_fail 283 /// # use core::sync::atomic::*; 284 /// # use radium::Radium; 285 /// # use core::ptr; 286 /// let ptr: AtomicPtr<usize> = Default::default(); 287 /// Radium::fetch_or(&ptr, ptr::null_mut(), Ordering::Relaxed); 288 /// ``` 289 pub trait BitOps {} 290 291 /// Types supporting maybe-atomic arithmetic operations. 292 /// 293 /// Types implementing this trait support the [`fetch_add`] and 294 /// [`fetch_sub`] maybe-atomic operations. 295 /// 296 /// [`fetch_add`]: crate::Radium::fetch_add 297 /// [`fetch_sub`]: crate::Radium::fetch_sub 298 /// 299 /// The integer types, such as `usize` and `i32`, implement this trait. 300 /// 301 /// ```rust 302 /// # use core::sync::atomic::*; 303 /// # use radium::Radium; 304 /// let num: AtomicUsize = AtomicUsize::new(2); 305 /// Radium::fetch_add(&num, 2, Ordering::Relaxed); 306 /// ``` 307 /// 308 /// `bool` and pointers do not. This will cause a compiler error. 309 /// 310 /// ```rust,compile_fail 311 /// # use core::sync::atomic::*; 312 /// # use radium::Radium; 313 /// let bit: AtomicBool = AtomicBool::new(false); 314 /// Radium::fetch_add(&bit, true, Ordering::Relaxed); 315 /// ``` 316 pub trait NumericOps: BitOps {} 317 } 318 319 macro_rules! radium { 320 // Emit the universal `Radium` trait function bodies for atomic types. 321 ( atom $base:ty ) => { 322 #[inline] 323 fn new(value: $base) -> Self { 324 Self::new(value) 325 } 326 327 #[inline] 328 fn fence(order: Ordering) { 329 core::sync::atomic::fence(order); 330 } 331 332 #[inline] 333 fn get_mut(&mut self) -> &mut $base { 334 self.get_mut() 335 } 336 337 #[inline] 338 fn into_inner(self) -> $base { 339 self.into_inner() 340 } 341 342 #[inline] 343 fn load(&self, order: Ordering) -> $base { 344 self.load(order) 345 } 346 347 #[inline] 348 fn store(&self, value: $base, order: Ordering) { 349 self.store(value, order); 350 } 351 352 #[inline] 353 fn swap(&self, value: $base, order: Ordering) -> $base { 354 self.swap(value, order) 355 } 356 357 #[inline] 358 fn compare_and_swap( 359 &self, 360 current: $base, 361 new: $base, 362 order: Ordering, 363 ) -> $base { 364 self.compare_and_swap(current, new, order) 365 } 366 367 #[inline] 368 fn compare_exchange( 369 &self, 370 current: $base, 371 new: $base, 372 success: Ordering, 373 failure: Ordering, 374 ) -> Result<$base, $base> { 375 self.compare_exchange(current, new, success, failure) 376 } 377 378 #[inline] 379 fn compare_exchange_weak( 380 &self, 381 current: $base, 382 new: $base, 383 success: Ordering, 384 failure: Ordering, 385 ) -> Result<$base, $base> { 386 self.compare_exchange_weak(current, new, success, failure) 387 } 388 }; 389 390 // Emit the `Radium` trait function bodies for bit-wise types. 391 ( atom_bit $base:ty ) => { 392 #[inline] 393 fn fetch_and(&self, value: $base, order: Ordering) -> $base { 394 self.fetch_and(value, order) 395 } 396 397 #[inline] 398 fn fetch_nand(&self, value: $base, order: Ordering) -> $base { 399 self.fetch_nand(value, order) 400 } 401 402 #[inline] 403 fn fetch_or(&self, value: $base, order: Ordering) -> $base { 404 self.fetch_or(value, order) 405 } 406 407 #[inline] 408 fn fetch_xor(&self, value: $base, order: Ordering) -> $base { 409 self.fetch_xor(value, order) 410 } 411 }; 412 413 // Emit the `Radium` trait function bodies for integral types. 414 ( atom_int $base:ty ) => { 415 #[inline] 416 fn fetch_add(&self, value: $base, order: Ordering) -> $base { 417 self.fetch_add(value, order) 418 } 419 420 #[inline] 421 fn fetch_sub(&self, value: $base, order: Ordering) -> $base { 422 self.fetch_sub(value, order) 423 } 424 }; 425 426 // Emit the universal `Radium` trait function bodies for `Cell<_>`. 427 ( cell $base:ty ) => { 428 #[inline] 429 fn new(value: $base) -> Self { 430 Cell::new(value) 431 } 432 433 #[inline] 434 fn fence(_: Ordering) {} 435 436 #[inline] 437 fn get_mut(&mut self) -> &mut $base { 438 self.get_mut() 439 } 440 441 #[inline] 442 fn into_inner(self) -> $base { 443 self.into_inner() 444 } 445 446 #[inline] 447 fn load(&self, _: Ordering) -> $base { 448 self.get() 449 } 450 451 #[inline] 452 fn store(&self, value: $base, _: Ordering) { 453 self.set(value); 454 } 455 456 #[inline] 457 fn swap(&self, value: $base, _: Ordering) -> $base { 458 self.replace(value) 459 } 460 461 #[inline] 462 fn compare_and_swap( 463 &self, 464 current: $base, 465 new: $base, 466 _: Ordering, 467 ) -> $base { 468 if self.get() == current { 469 self.replace(new) 470 } else { 471 self.get() 472 } 473 } 474 475 #[inline] 476 fn compare_exchange( 477 &self, 478 current: $base, 479 new: $base, 480 _: Ordering, 481 _: Ordering, 482 ) -> Result<$base, $base> { 483 if self.get() == current { 484 Ok(self.replace(new)) 485 } else { 486 Err(self.get()) 487 } 488 } 489 490 #[inline] 491 fn compare_exchange_weak( 492 &self, 493 current: $base, 494 new: $base, 495 success: Ordering, 496 failure: Ordering, 497 ) -> Result<$base, $base> { 498 Radium::compare_exchange(self, current, new, success, failure) 499 } 500 }; 501 502 // Emit the `Radium` trait function bodies for bit-wise types. 503 ( cell_bit $base:ty ) => { 504 #[inline] 505 fn fetch_and(&self, value: $base, _: Ordering) -> $base { 506 self.replace(self.get() & value) 507 } 508 509 #[inline] 510 fn fetch_nand(&self, value: $base, _: Ordering) -> $base { 511 self.replace(!(self.get() & value)) 512 } 513 514 #[inline] 515 fn fetch_or(&self, value: $base, _: Ordering) -> $base { 516 self.replace(self.get() | value) 517 } 518 519 #[inline] 520 fn fetch_xor(&self, value: $base, _: Ordering) -> $base { 521 self.replace(self.get() ^ value) 522 } 523 }; 524 525 // Emit the `Radium` trait function bodies for integral types. 526 ( cell_int $base:ty ) => { 527 #[inline] 528 fn fetch_add(&self, value: $base, _: Ordering) -> $base { 529 self.replace(self.get().wrapping_add(value)) 530 } 531 532 #[inline] 533 fn fetch_sub(&self, value: $base, _: Ordering) -> $base { 534 self.replace(self.get().wrapping_sub(value)) 535 } 536 }; 537 538 // Implement `Radium` for integral fundamentals. 539 ( int $flag:ident $( $base:ty , $atom:ty ; )* ) => { $( 540 impl marker::BitOps for $base {} 541 impl marker::NumericOps for $base {} 542 543 #[cfg($flag)] 544 impl Radium for $atom { 545 type Item = $base; 546 547 radium!(atom $base); 548 radium!(atom_bit $base); 549 radium!(atom_int $base); 550 } 551 552 impl Radium for Cell<$base> { 553 type Item = $base; 554 555 radium!(cell $base); 556 radium!(cell_bit $base); 557 radium!(cell_int $base); 558 } 559 )* }; 560 } 561 562 radium![int radium_atomic_8 i8, AtomicI8; u8, AtomicU8;]; 563 radium![int radium_atomic_16 i16, AtomicI16; u16, AtomicU16;]; 564 radium![int radium_atomic_32 i32, AtomicI32; u32, AtomicU32;]; 565 radium![int radium_atomic_64 i64, AtomicI64; u64, AtomicU64;]; 566 radium![int radium_atomic_ptr isize, AtomicIsize; usize, AtomicUsize;]; 567 568 impl marker::BitOps for bool {} 569 570 #[cfg(radium_atomic_8)] 571 impl Radium for AtomicBool { 572 type Item = bool; 573 574 radium!(atom bool); 575 radium!(atom_bit bool); 576 577 /// ```compile_fail 578 /// # use std::{ptr, sync::atomic::*, cell::*}; 579 /// # use radium::*; 580 /// let atom = AtomicBool::new(false); 581 /// Radium::fetch_add(&atom, true, Ordering::Relaxed); 582 /// ``` 583 #[doc(hidden)] fetch_add(&self, _value: bool, _order: Ordering) -> bool584 fn fetch_add(&self, _value: bool, _order: Ordering) -> bool { 585 unreachable!("This method statically cannot be called") 586 } 587 588 /// ```compile_fail 589 /// # use std::{ptr, sync::atomic::*, cell::*}; 590 /// # use radium::*; 591 /// let atom = AtomicBool::new(false); 592 /// Radium::fetch_sub(&atom, true, Ordering::Relaxed); 593 /// ``` 594 #[doc(hidden)] fetch_sub(&self, _value: bool, _order: Ordering) -> bool595 fn fetch_sub(&self, _value: bool, _order: Ordering) -> bool { 596 unreachable!("This method statically cannot be called") 597 } 598 } 599 600 impl Radium for Cell<bool> { 601 type Item = bool; 602 603 radium!(cell bool); 604 radium!(cell_bit bool); 605 606 /// ```compile_fail 607 /// # use std::{ptr, sync::atomic::*, cell::*}; 608 /// # use radium::*; 609 /// let cell = Cell::<bool>::new(false); 610 /// Radium::fetch_add(&cell, true, Ordering::Relaxed); 611 /// ``` 612 #[doc(hidden)] fetch_add(&self, _value: bool, _order: Ordering) -> bool613 fn fetch_add(&self, _value: bool, _order: Ordering) -> bool { 614 unreachable!("This method statically cannot be called") 615 } 616 617 /// ```compile_fail 618 /// # use std::{ptr, sync::atomic::*, cell::*}; 619 /// # use radium::*; 620 /// let cell = Cell::<bool>::new(false); 621 /// Radium::fetch_sub(&cell, true, Ordering::Relaxed); 622 /// ``` 623 #[doc(hidden)] fetch_sub(&self, _value: bool, _order: Ordering) -> bool624 fn fetch_sub(&self, _value: bool, _order: Ordering) -> bool { 625 unreachable!("This method statically cannot be called") 626 } 627 } 628 629 #[cfg(radium_atomic_ptr)] 630 impl<T> Radium for AtomicPtr<T> { 631 type Item = *mut T; 632 633 radium!(atom *mut T); 634 635 /// ```compile_fail 636 /// # use std::{ptr, sync::atomic::*, cell::*}; 637 /// # use radium::*; 638 /// let atom = AtomicPtr::<u8>::new(ptr::null_mut()); 639 /// Radium::fetch_and(&atom, ptr::null_mut(), Ordering::Relaxed); 640 /// ``` 641 #[doc(hidden)] fetch_and(&self, _value: *mut T, _order: Ordering) -> *mut T642 fn fetch_and(&self, _value: *mut T, _order: Ordering) -> *mut T { 643 unreachable!("This method statically cannot be called") 644 } 645 646 /// ```compile_fail 647 /// # use std::{ptr, sync::atomic::*, cell::*}; 648 /// # use radium::*; 649 /// let atom = AtomicPtr::<u8>::new(ptr::null_mut()); 650 /// Radium::fetch_nand(&atom, ptr::null_mut(), Ordering::Relaxed); 651 /// ``` 652 #[doc(hidden)] fetch_nand(&self, _value: *mut T, _order: Ordering) -> *mut T653 fn fetch_nand(&self, _value: *mut T, _order: Ordering) -> *mut T { 654 unreachable!("This method statically cannot be called") 655 } 656 657 /// ```compile_fail 658 /// # use std::{ptr, sync::atomic::*, cell::*}; 659 /// # use radium::*; 660 /// let atom = AtomicPtr::<u8>::new(ptr::null_mut()); 661 /// Radium::fetch_or(&atom, ptr::null_mut(), Ordering::Relaxed); 662 /// ``` 663 #[doc(hidden)] fetch_or(&self, _value: *mut T, _order: Ordering) -> *mut T664 fn fetch_or(&self, _value: *mut T, _order: Ordering) -> *mut T { 665 unreachable!("This method statically cannot be called") 666 } 667 668 /// ```compile_fail 669 /// # use std::{ptr, sync::atomic::*, cell::*}; 670 /// # use radium::*; 671 /// let atom = AtomicPtr::<u8>::new(ptr::null_mut()); 672 /// Radium::fetch_xor(&atom, ptr::null_mut(), Ordering::Relaxed); 673 /// ``` 674 #[doc(hidden)] fetch_xor(&self, _value: *mut T, _order: Ordering) -> *mut T675 fn fetch_xor(&self, _value: *mut T, _order: Ordering) -> *mut T { 676 unreachable!("This method statically cannot be called") 677 } 678 679 /// ```compile_fail 680 /// # use std::{ptr, sync::atomic::*, cell::*}; 681 /// # use radium::*; 682 /// let atom = AtomicPtr::<u8>::new(ptr::null_mut()); 683 /// Radium::fetch_add(&atom, ptr::null_mut(), Ordering::Relaxed); 684 /// ``` 685 #[doc(hidden)] fetch_add(&self, _value: *mut T, _order: Ordering) -> *mut T686 fn fetch_add(&self, _value: *mut T, _order: Ordering) -> *mut T { 687 unreachable!("This method statically cannot be called") 688 } 689 690 /// ```compile_fail 691 /// # use std::{ptr, sync::atomic::*, cell::*}; 692 /// # use radium::*; 693 /// let atom = AtomicPtr::<u8>::new(ptr::null_mut()); 694 /// Radium::fetch_sub(&atom, ptr::null_mut(), Ordering::Relaxed); 695 /// ``` 696 #[doc(hidden)] fetch_sub(&self, _value: *mut T, _order: Ordering) -> *mut T697 fn fetch_sub(&self, _value: *mut T, _order: Ordering) -> *mut T { 698 unreachable!("This method statically cannot be called") 699 } 700 } 701 702 impl<T> Radium for Cell<*mut T> { 703 type Item = *mut T; 704 705 radium!(cell *mut T); 706 707 /// ```compile_fail 708 /// # use std::{ptr, sync::atomic::*, cell::*}; 709 /// # use radium::*; 710 /// let cell = Cell::<*mut u8>::new(ptr::null_mut()); 711 /// Radium::fetch_and(&cell, ptr::null_mut(), Ordering::Relaxed); 712 /// ``` 713 #[doc(hidden)] fetch_and(&self, _value: *mut T, _order: Ordering) -> *mut T714 fn fetch_and(&self, _value: *mut T, _order: Ordering) -> *mut T { 715 unreachable!("This method statically cannot be called") 716 } 717 718 /// ```compile_fail 719 /// # use std::{ptr, sync::atomic::*, cell::*}; 720 /// # use radium::*; 721 /// let cell = Cell::<*mut u8>::new(ptr::null_mut()); 722 /// Radium::fetch_nand(&cell, ptr::null_mut(), Ordering::Relaxed); 723 /// ``` 724 #[doc(hidden)] fetch_nand(&self, _value: *mut T, _order: Ordering) -> *mut T725 fn fetch_nand(&self, _value: *mut T, _order: Ordering) -> *mut T { 726 unreachable!("This method statically cannot be called") 727 } 728 729 /// ```compile_fail 730 /// # use std::{ptr, sync::atomic::*, cell::*}; 731 /// # use radium::*; 732 /// let cell = Cell::<*mut u8>::new(ptr::null_mut()); 733 /// Radium::fetch_or(&cell, ptr::null_mut(), Ordering::Relaxed); 734 /// ``` 735 #[doc(hidden)] fetch_or(&self, _value: *mut T, _order: Ordering) -> *mut T736 fn fetch_or(&self, _value: *mut T, _order: Ordering) -> *mut T { 737 unreachable!("This method statically cannot be called") 738 } 739 740 /// ```compile_fail 741 /// # use std::{ptr, sync::atomic::*, cell::*}; 742 /// # use radium::*; 743 /// let cell = Cell::<*mut u8>::new(ptr::null_mut()); 744 /// Radium::fetch_xor(&cell, ptr::null_mut(), Ordering::Relaxed); 745 /// ``` 746 #[doc(hidden)] fetch_xor(&self, _value: *mut T, _order: Ordering) -> *mut T747 fn fetch_xor(&self, _value: *mut T, _order: Ordering) -> *mut T { 748 unreachable!("This method statically cannot be called") 749 } 750 751 /// ```compile_fail 752 /// # use std::{ptr, sync::atomic::*, cell::*}; 753 /// # use radium::*; 754 /// let cell = Cell::<*mut u8>::new(ptr::null_mut()); 755 /// Radium::fetch_add(&cell, ptr::null_mut(), Ordering::Relaxed); 756 /// ``` 757 #[doc(hidden)] fetch_add(&self, _value: *mut T, _order: Ordering) -> *mut T758 fn fetch_add(&self, _value: *mut T, _order: Ordering) -> *mut T { 759 unreachable!("This method statically cannot be called") 760 } 761 762 /// ```compile_fail 763 /// # use std::{ptr, sync::atomic::*, cell::*}; 764 /// # use radium::*; 765 /// let cell = Cell::<*mut u8>::new(ptr::null_mut()); 766 /// Radium::fetch_sub(&cell, ptr::null_mut(), Ordering::Relaxed); 767 /// ``` 768 #[doc(hidden)] fetch_sub(&self, _value: *mut T, _order: Ordering) -> *mut T769 fn fetch_sub(&self, _value: *mut T, _order: Ordering) -> *mut T { 770 unreachable!("This method statically cannot be called") 771 } 772 } 773 774 #[cfg(test)] 775 mod tests { 776 use super::*; 777 use core::cell::Cell; 778 779 #[test] absent_traits()780 fn absent_traits() { 781 static_assertions::assert_not_impl_any!(bool: marker::NumericOps); 782 static_assertions::assert_not_impl_any!(*mut u8: marker::BitOps, marker::NumericOps); 783 } 784 785 #[test] present_traits()786 fn present_traits() { 787 static_assertions::assert_impl_all!(bool: marker::BitOps); 788 static_assertions::assert_impl_all!(usize: marker::BitOps, marker::NumericOps); 789 } 790 791 #[test] always_cell()792 fn always_cell() { 793 static_assertions::assert_impl_all!(Cell<bool>: Radium<Item = bool>); 794 static_assertions::assert_impl_all!(Cell<i8>: Radium<Item = i8>); 795 static_assertions::assert_impl_all!(Cell<u8>: Radium<Item = u8>); 796 static_assertions::assert_impl_all!(Cell<i16>: Radium<Item = i16>); 797 static_assertions::assert_impl_all!(Cell<u16>: Radium<Item = u16>); 798 static_assertions::assert_impl_all!(Cell<i32>: Radium<Item = i32>); 799 static_assertions::assert_impl_all!(Cell<u32>: Radium<Item = u32>); 800 static_assertions::assert_impl_all!(Cell<i64>: Radium<Item = i64>); 801 static_assertions::assert_impl_all!(Cell<u64>: Radium<Item = u64>); 802 static_assertions::assert_impl_all!(Cell<isize>: Radium<Item = isize>); 803 static_assertions::assert_impl_all!(Cell<usize>: Radium<Item = usize>); 804 static_assertions::assert_impl_all!(Cell<*mut ()>: Radium<Item = *mut ()>); 805 } 806 807 #[test] always_alias()808 fn always_alias() { 809 static_assertions::assert_impl_all!(types::RadiumBool: Radium<Item = bool>); 810 static_assertions::assert_impl_all!(types::RadiumI8: Radium<Item = i8>); 811 static_assertions::assert_impl_all!(types::RadiumU8: Radium<Item = u8>); 812 static_assertions::assert_impl_all!(types::RadiumI16: Radium<Item = i16>); 813 static_assertions::assert_impl_all!(types::RadiumU16: Radium<Item = u16>); 814 static_assertions::assert_impl_all!(types::RadiumI32: Radium<Item = i32>); 815 static_assertions::assert_impl_all!(types::RadiumU32: Radium<Item = u32>); 816 static_assertions::assert_impl_all!(types::RadiumI64: Radium<Item = i64>); 817 static_assertions::assert_impl_all!(types::RadiumU64: Radium<Item = u64>); 818 static_assertions::assert_impl_all!(types::RadiumIsize: Radium<Item = isize>); 819 static_assertions::assert_impl_all!(types::RadiumUsize: Radium<Item = usize>); 820 static_assertions::assert_impl_all!(types::RadiumPtr<()>: Radium<Item = *mut ()>); 821 } 822 } 823