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