xref: /DragonOS/kernel/src/libs/int_like.rs (revision c635d8a9cfe25bc11779f323ef0c7d7a0f597d4a)
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