xref: /DragonOS/kernel/src/libs/int_like.rs (revision e28411791f090c421fe4b6fa5956fb1bd362a8d9)
1bb24249fSLoGin //! These code are bring from redox-os, and I think it's a good idea to use it in our project.
2bb24249fSLoGin //!
3bb24249fSLoGin //! Helpers used to define types that are backed by integers (typically `usize`),
4bb24249fSLoGin //! without compromising safety.
5bb24249fSLoGin //!
6bb24249fSLoGin //! # Example
7bb24249fSLoGin //!
8bb24249fSLoGin //! ```
9bb24249fSLoGin //! /// Define an opaque type `Pid` backed by a `usize`.
10bb24249fSLoGin //! int_like!(Pid, usize);
11bb24249fSLoGin //!
12bb24249fSLoGin //! const ZERO: Pid = Pid::from(0);
13bb24249fSLoGin //! ```
14bb24249fSLoGin //!
15bb24249fSLoGin //! # Example
16bb24249fSLoGin //!
17bb24249fSLoGin //! ```
18bb24249fSLoGin //! /// Define opaque types `Pid` and `AtomicPid`, backed respectively by a `usize`
19bb24249fSLoGin //! /// and a `AtomicUsize`.
20bb24249fSLoGin //!
21bb24249fSLoGin //! int_like!(Pid, AtomicPid, usize, AtomicUsize);
22bb24249fSLoGin //!
23bb24249fSLoGin //! const ZERO: Pid = Pid::from(0);
24bb24249fSLoGin //! let ATOMIC_PID: AtomicPid = AtomicPid::default();
25bb24249fSLoGin //! ```
26bb24249fSLoGin 
27bb24249fSLoGin #[macro_export]
28bb24249fSLoGin macro_rules! int_like {
29bb24249fSLoGin     ($new_type_name:ident, $backing_type: ident) => {
30*e2841179SLoGin         #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy, Hash)]
31bb24249fSLoGin         pub struct $new_type_name($backing_type);
32bb24249fSLoGin 
33bb24249fSLoGin         impl $new_type_name {
34bb24249fSLoGin             #[allow(dead_code)]
35bb24249fSLoGin             pub const fn into(self) -> $backing_type {
36bb24249fSLoGin                 self.0
37bb24249fSLoGin             }
38bb24249fSLoGin             #[allow(dead_code)]
39bb24249fSLoGin             pub const fn from(x: $backing_type) -> Self {
40bb24249fSLoGin                 $new_type_name(x)
41bb24249fSLoGin             }
421496ba7bSLoGin 
431496ba7bSLoGin             #[allow(dead_code)]
441496ba7bSLoGin             pub const fn new(x: $backing_type) -> Self {
451496ba7bSLoGin                 Self::from(x)
461496ba7bSLoGin             }
47a03c4f9dSLoGin 
48a03c4f9dSLoGin             #[allow(dead_code)]
49a03c4f9dSLoGin             pub const fn data(&self) -> $backing_type {
50a03c4f9dSLoGin                 self.0
51a03c4f9dSLoGin             }
52bb24249fSLoGin         }
53bb24249fSLoGin     };
54bb24249fSLoGin 
55bb24249fSLoGin     ($new_type_name:ident, $new_atomic_type_name: ident, $backing_type:ident, $backing_atomic_type:ident) => {
56bb24249fSLoGin         int_like!($new_type_name, $backing_type);
57bb24249fSLoGin 
58bb24249fSLoGin         /// A mutable holder for T that can safely be shared among threads.
59bb24249fSLoGin         /// Runtime equivalent to using `AtomicUsize`, just type-safer.
601496ba7bSLoGin         #[derive(Debug)]
61bb24249fSLoGin         pub struct $new_atomic_type_name {
62bb24249fSLoGin             container: $backing_atomic_type,
63bb24249fSLoGin         }
64bb24249fSLoGin 
65bb24249fSLoGin         impl $new_atomic_type_name {
66bb24249fSLoGin             #[allow(dead_code)]
67bb24249fSLoGin             pub const fn new(x: $new_type_name) -> Self {
68bb24249fSLoGin                 $new_atomic_type_name {
69aa0367d6SLoGin                     container: $backing_atomic_type::new(x.into()),
70bb24249fSLoGin                 }
71bb24249fSLoGin             }
72bb24249fSLoGin             #[allow(dead_code)]
73bb24249fSLoGin             pub const fn default() -> Self {
74bb24249fSLoGin                 Self::new($new_type_name::from(0))
75bb24249fSLoGin             }
76bb24249fSLoGin             #[allow(dead_code)]
77bb24249fSLoGin             pub fn load(&self, order: ::core::sync::atomic::Ordering) -> $new_type_name {
78bb24249fSLoGin                 $new_type_name::from(self.container.load(order))
79bb24249fSLoGin             }
80bb24249fSLoGin             #[allow(dead_code)]
81bb24249fSLoGin             pub fn store(&self, val: $new_type_name, order: ::core::sync::atomic::Ordering) {
82bb24249fSLoGin                 self.container.store(val.into(), order)
83bb24249fSLoGin             }
84bb24249fSLoGin             #[allow(dead_code)]
85aa0367d6SLoGin             pub fn swap(
86aa0367d6SLoGin                 &self,
87aa0367d6SLoGin                 val: $new_type_name,
88aa0367d6SLoGin                 order: ::core::sync::atomic::Ordering,
89aa0367d6SLoGin             ) -> $new_type_name {
90bb24249fSLoGin                 $new_type_name::from(self.container.swap(val.into(), order))
91bb24249fSLoGin             }
92bb24249fSLoGin             #[allow(dead_code)]
93aa0367d6SLoGin             pub fn compare_exchange(
94aa0367d6SLoGin                 &self,
95aa0367d6SLoGin                 current: $new_type_name,
96aa0367d6SLoGin                 new: $new_type_name,
97aa0367d6SLoGin                 success: ::core::sync::atomic::Ordering,
98aa0367d6SLoGin                 failure: ::core::sync::atomic::Ordering,
99aa0367d6SLoGin             ) -> ::core::result::Result<$new_type_name, $new_type_name> {
100aa0367d6SLoGin                 match self
101aa0367d6SLoGin                     .container
102aa0367d6SLoGin                     .compare_exchange(current.into(), new.into(), success, failure)
103aa0367d6SLoGin                 {
104bb24249fSLoGin                     Ok(result) => Ok($new_type_name::from(result)),
105aa0367d6SLoGin                     Err(result) => Err($new_type_name::from(result)),
106bb24249fSLoGin                 }
107bb24249fSLoGin             }
108bb24249fSLoGin             #[allow(dead_code)]
109aa0367d6SLoGin             pub fn compare_exchange_weak(
110aa0367d6SLoGin                 &self,
111aa0367d6SLoGin                 current: $new_type_name,
112aa0367d6SLoGin                 new: $new_type_name,
113aa0367d6SLoGin                 success: ::core::sync::atomic::Ordering,
114aa0367d6SLoGin                 failure: ::core::sync::atomic::Ordering,
115aa0367d6SLoGin             ) -> ::core::result::Result<$new_type_name, $new_type_name> {
116aa0367d6SLoGin                 match self.container.compare_exchange_weak(
117aa0367d6SLoGin                     current.into(),
118aa0367d6SLoGin                     new.into(),
119aa0367d6SLoGin                     success,
120aa0367d6SLoGin                     failure,
121aa0367d6SLoGin                 ) {
122bb24249fSLoGin                     Ok(result) => Ok($new_type_name::from(result)),
123aa0367d6SLoGin                     Err(result) => Err($new_type_name::from(result)),
124bb24249fSLoGin                 }
125bb24249fSLoGin             }
1261496ba7bSLoGin             #[allow(dead_code)]
1271496ba7bSLoGin             pub fn fetch_add(
1281496ba7bSLoGin                 &self,
1291496ba7bSLoGin                 val: $new_type_name,
1301496ba7bSLoGin                 order: ::core::sync::atomic::Ordering,
1311496ba7bSLoGin             ) -> $new_type_name {
1321496ba7bSLoGin                 $new_type_name::from(self.container.fetch_add(val.into(), order))
1331496ba7bSLoGin             }
134bb24249fSLoGin         }
135aa0367d6SLoGin     };
136bb24249fSLoGin }
137bb24249fSLoGin 
138bb24249fSLoGin #[test]
test()139bb24249fSLoGin fn test() {
140bb24249fSLoGin     use ::core::sync::atomic::AtomicUsize;
141aa0367d6SLoGin     use core::mem::size_of;
142bb24249fSLoGin 
143bb24249fSLoGin     // Generate type `usize_like`.
144bb24249fSLoGin     int_like!(UsizeLike, usize);
145bb24249fSLoGin     assert_eq!(size_of::<UsizeLike>(), size_of::<usize>());
146bb24249fSLoGin 
147bb24249fSLoGin     // Generate types `usize_like` and `AtomicUsize`.
148bb24249fSLoGin     int_like!(UsizeLike2, AtomicUsizeLike, usize, AtomicUsize);
149bb24249fSLoGin     assert_eq!(size_of::<UsizeLike2>(), size_of::<usize>());
150bb24249fSLoGin     assert_eq!(size_of::<AtomicUsizeLike>(), size_of::<AtomicUsize>());
151bb24249fSLoGin }
152