1 //! These code are bring from redox-os, and I think it's a good idea to use it in our project. 2 //! 3 //! Helpers used to define types that are backed by integers (typically `usize`), 4 //! without compromising safety. 5 //! 6 //! # Example 7 //! 8 //! ``` 9 //! /// Define an opaque type `Pid` backed by a `usize`. 10 //! int_like!(Pid, usize); 11 //! 12 //! const ZERO: Pid = Pid::from(0); 13 //! ``` 14 //! 15 //! # Example 16 //! 17 //! ``` 18 //! /// Define opaque types `Pid` and `AtomicPid`, backed respectively by a `usize` 19 //! /// and a `AtomicUsize`. 20 //! 21 //! int_like!(Pid, AtomicPid, usize, AtomicUsize); 22 //! 23 //! const ZERO: Pid = Pid::from(0); 24 //! let ATOMIC_PID: AtomicPid = AtomicPid::default(); 25 //! ``` 26 27 #[macro_export] 28 macro_rules! int_like { 29 ($new_type_name:ident, $backing_type: ident) => { 30 #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] 31 pub struct $new_type_name($backing_type); 32 33 impl $new_type_name { 34 #[allow(dead_code)] 35 pub const fn into(self) -> $backing_type { 36 self.0 37 } 38 #[allow(dead_code)] 39 pub const fn from(x: $backing_type) -> Self { 40 $new_type_name(x) 41 } 42 } 43 }; 44 45 ($new_type_name:ident, $new_atomic_type_name: ident, $backing_type:ident, $backing_atomic_type:ident) => { 46 int_like!($new_type_name, $backing_type); 47 48 /// A mutable holder for T that can safely be shared among threads. 49 /// Runtime equivalent to using `AtomicUsize`, just type-safer. 50 pub struct $new_atomic_type_name { 51 container: $backing_atomic_type, 52 } 53 54 impl $new_atomic_type_name { 55 #[allow(dead_code)] 56 pub const fn new(x: $new_type_name) -> Self { 57 $new_atomic_type_name { 58 container: $backing_atomic_type::new(x.into()), 59 } 60 } 61 #[allow(dead_code)] 62 pub const fn default() -> Self { 63 Self::new($new_type_name::from(0)) 64 } 65 #[allow(dead_code)] 66 pub fn load(&self, order: ::core::sync::atomic::Ordering) -> $new_type_name { 67 $new_type_name::from(self.container.load(order)) 68 } 69 #[allow(dead_code)] 70 pub fn store(&self, val: $new_type_name, order: ::core::sync::atomic::Ordering) { 71 self.container.store(val.into(), order) 72 } 73 #[allow(dead_code)] 74 pub fn swap( 75 &self, 76 val: $new_type_name, 77 order: ::core::sync::atomic::Ordering, 78 ) -> $new_type_name { 79 $new_type_name::from(self.container.swap(val.into(), order)) 80 } 81 #[allow(dead_code)] 82 pub fn compare_exchange( 83 &self, 84 current: $new_type_name, 85 new: $new_type_name, 86 success: ::core::sync::atomic::Ordering, 87 failure: ::core::sync::atomic::Ordering, 88 ) -> ::core::result::Result<$new_type_name, $new_type_name> { 89 match self 90 .container 91 .compare_exchange(current.into(), new.into(), success, failure) 92 { 93 Ok(result) => Ok($new_type_name::from(result)), 94 Err(result) => Err($new_type_name::from(result)), 95 } 96 } 97 #[allow(dead_code)] 98 pub fn compare_exchange_weak( 99 &self, 100 current: $new_type_name, 101 new: $new_type_name, 102 success: ::core::sync::atomic::Ordering, 103 failure: ::core::sync::atomic::Ordering, 104 ) -> ::core::result::Result<$new_type_name, $new_type_name> { 105 match self.container.compare_exchange_weak( 106 current.into(), 107 new.into(), 108 success, 109 failure, 110 ) { 111 Ok(result) => Ok($new_type_name::from(result)), 112 Err(result) => Err($new_type_name::from(result)), 113 } 114 } 115 } 116 }; 117 } 118 119 #[test] 120 fn test() { 121 use ::core::sync::atomic::AtomicUsize; 122 use core::mem::size_of; 123 124 // Generate type `usize_like`. 125 int_like!(UsizeLike, usize); 126 assert_eq!(size_of::<UsizeLike>(), size_of::<usize>()); 127 128 // Generate types `usize_like` and `AtomicUsize`. 129 int_like!(UsizeLike2, AtomicUsizeLike, usize, AtomicUsize); 130 assert_eq!(size_of::<UsizeLike2>(), size_of::<usize>()); 131 assert_eq!(size_of::<AtomicUsizeLike>(), size_of::<AtomicUsize>()); 132 } 133