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