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, Hash)] 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 #[allow(dead_code)] 44 pub const fn new(x: $backing_type) -> Self { 45 Self::from(x) 46 } 47 48 #[allow(dead_code)] 49 pub const fn data(&self) -> $backing_type { 50 self.0 51 } 52 } 53 }; 54 55 ($new_type_name:ident, $new_atomic_type_name: ident, $backing_type:ident, $backing_atomic_type:ident) => { 56 int_like!($new_type_name, $backing_type); 57 58 /// A mutable holder for T that can safely be shared among threads. 59 /// Runtime equivalent to using `AtomicUsize`, just type-safer. 60 #[derive(Debug)] 61 pub struct $new_atomic_type_name { 62 container: $backing_atomic_type, 63 } 64 65 impl $new_atomic_type_name { 66 #[allow(dead_code)] 67 pub const fn new(x: $new_type_name) -> Self { 68 $new_atomic_type_name { 69 container: $backing_atomic_type::new(x.into()), 70 } 71 } 72 #[allow(dead_code)] 73 pub const fn default() -> Self { 74 Self::new($new_type_name::from(0)) 75 } 76 #[allow(dead_code)] 77 pub fn load(&self, order: ::core::sync::atomic::Ordering) -> $new_type_name { 78 $new_type_name::from(self.container.load(order)) 79 } 80 #[allow(dead_code)] 81 pub fn store(&self, val: $new_type_name, order: ::core::sync::atomic::Ordering) { 82 self.container.store(val.into(), order) 83 } 84 #[allow(dead_code)] 85 pub fn swap( 86 &self, 87 val: $new_type_name, 88 order: ::core::sync::atomic::Ordering, 89 ) -> $new_type_name { 90 $new_type_name::from(self.container.swap(val.into(), order)) 91 } 92 #[allow(dead_code)] 93 pub fn compare_exchange( 94 &self, 95 current: $new_type_name, 96 new: $new_type_name, 97 success: ::core::sync::atomic::Ordering, 98 failure: ::core::sync::atomic::Ordering, 99 ) -> ::core::result::Result<$new_type_name, $new_type_name> { 100 match self 101 .container 102 .compare_exchange(current.into(), new.into(), success, failure) 103 { 104 Ok(result) => Ok($new_type_name::from(result)), 105 Err(result) => Err($new_type_name::from(result)), 106 } 107 } 108 #[allow(dead_code)] 109 pub fn compare_exchange_weak( 110 &self, 111 current: $new_type_name, 112 new: $new_type_name, 113 success: ::core::sync::atomic::Ordering, 114 failure: ::core::sync::atomic::Ordering, 115 ) -> ::core::result::Result<$new_type_name, $new_type_name> { 116 match self.container.compare_exchange_weak( 117 current.into(), 118 new.into(), 119 success, 120 failure, 121 ) { 122 Ok(result) => Ok($new_type_name::from(result)), 123 Err(result) => Err($new_type_name::from(result)), 124 } 125 } 126 #[allow(dead_code)] 127 pub fn fetch_add( 128 &self, 129 val: $new_type_name, 130 order: ::core::sync::atomic::Ordering, 131 ) -> $new_type_name { 132 $new_type_name::from(self.container.fetch_add(val.into(), order)) 133 } 134 } 135 }; 136 } 137 138 #[test] 139 fn test() { 140 use ::core::sync::atomic::AtomicUsize; 141 use core::mem::size_of; 142 143 // Generate type `usize_like`. 144 int_like!(UsizeLike, usize); 145 assert_eq!(size_of::<UsizeLike>(), size_of::<usize>()); 146 147 // Generate types `usize_like` and `AtomicUsize`. 148 int_like!(UsizeLike2, AtomicUsizeLike, usize, AtomicUsize); 149 assert_eq!(size_of::<UsizeLike2>(), size_of::<usize>()); 150 assert_eq!(size_of::<AtomicUsizeLike>(), size_of::<AtomicUsize>()); 151 } 152