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]
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