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