radium/
macros.rs

1#[doc(hidden)]
2#[macro_export]
3#[cfg(radium_atomic_8)]
4macro_rules! __radium_if_atomic_8 {
5    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
6}
7
8#[doc(hidden)]
9#[macro_export]
10#[cfg(not(radium_atomic_8))]
11macro_rules! __radium_if_atomic_8 {
12    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
13}
14
15#[doc(hidden)]
16#[macro_export]
17#[cfg(radium_atomic_16)]
18macro_rules! __radium_if_atomic_16 {
19    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
20}
21
22#[doc(hidden)]
23#[macro_export]
24#[cfg(not(radium_atomic_16))]
25macro_rules! __radium_if_atomic_16 {
26    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
27}
28
29#[doc(hidden)]
30#[macro_export]
31#[cfg(radium_atomic_32)]
32macro_rules! __radium_if_atomic_32 {
33    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
34}
35
36#[doc(hidden)]
37#[macro_export]
38#[cfg(not(radium_atomic_32))]
39macro_rules! __radium_if_atomic_32 {
40    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
41}
42
43#[doc(hidden)]
44#[macro_export]
45#[cfg(radium_atomic_64)]
46macro_rules! __radium_if_atomic_64 {
47    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
48}
49
50#[doc(hidden)]
51#[macro_export]
52#[cfg(not(radium_atomic_64))]
53macro_rules! __radium_if_atomic_64 {
54    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
55}
56
57#[doc(hidden)]
58#[macro_export]
59#[cfg(radium_atomic_ptr)]
60macro_rules! __radium_if_atomic_ptr {
61    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
62}
63
64#[doc(hidden)]
65#[macro_export]
66#[cfg(not(radium_atomic_ptr))]
67macro_rules! __radium_if_atomic_ptr {
68    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
69}
70
71/// Conditional compilation based on the presence of atomic instructions.
72///
73/// This macro allows you to write `if`/`else` clauses, evaluated at
74/// compile-time, that test the presence of atomic instructions and preserve or
75/// destroy their guarded code accordingly.
76///
77/// The `if atomic(WIDTH)` test preserves the contents of its block when the
78/// target architecture has atomic instructions for the requested `WIDTH`, and
79/// removes them from the syntax tree when the target does not. If an `else`
80/// clause is provided, the contents of the `else` block are used as a
81/// substitute when the `if` is destroyed.
82///
83/// This macro can be used in any position. When it is used in item or statement
84/// position, it can contain multiple `if` clauses, and each will be evaluated
85/// in turn. Expression and type positions can only accept exactly one code
86/// span, and so may only have exactly one `if`/`else` clause. An `else` clause
87/// is required here so that the macro will always expand to something; an empty
88/// expansion is a parse error.
89///
90/// # Macro Syntax
91///
92/// The macro contents `if atomic() {} else {}` are part of the macro
93/// invocation. Only the contents of the two blocks are actual Rust code.
94///
95/// The acceptable arguments to `atomic()` are:
96///
97/// - `8`
98/// - `16`
99/// - `32`
100/// - `64`
101/// - `ptr`
102/// - `bool`: alias for `8`
103/// - `size`: alias for `ptr`
104///
105/// In addition, the `atomic()` test can be inverted, as `!atomic()`, to reverse
106/// the preserve/destroy behavior of the `if` and `else` blocks.
107///
108/// # Examples
109///
110/// This demonstrates the use of `if_atomic!` to produce multiple statements,
111/// and then to produce a single type-name.
112///
113/// ```rust
114/// radium::if_atomic! {
115///   if atomic(size) { use core::sync::atomic::AtomicUsize; }
116///   if !atomic(size) { use core::cell::Cell; }
117/// }
118///
119/// struct RadiumRc<T: ?Sized> {
120///   strong: radium::if_atomic! {
121///     if atomic(ptr) { AtomicUsize }
122///     else { Cell<usize> }
123///   },
124///   weak: radium::types::RadiumUsize,
125///   data: T,
126/// }
127/// ```
128#[macro_export]
129macro_rules! if_atomic {
130    ( if atomic(8) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
131        $crate::__radium_if_atomic_8! {
132            [ $($a)* ] [ $( $($b)* )? ]
133        }
134        $($crate::if_atomic! { if $($rest)* })?
135    };
136
137    ( if atomic(16) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
138        $crate::__radium_if_atomic_16! {
139            [ $($a)* ] [ $( $($b)* )? ]
140        }
141        $( $crate::if_atomic! { if $($rest)* } )?
142    };
143
144    ( if atomic(32) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
145        $crate::__radium_if_atomic_32! {
146            [ $($a)* ] [ $( $($b)* )? ]
147        }
148        $( $crate::if_atomic! { if $($rest)* } )?
149    };
150
151    ( if atomic(64) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
152        $crate::__radium_if_atomic_64! {
153            [ $($a)* ] [ $( $($b)* )? ]
154        }
155        $( $crate::if_atomic! { if $($rest)* } )?
156    };
157
158    ( if atomic(ptr) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
159        $crate::__radium_if_atomic_ptr! {
160            [ $($a)* ] [ $( $($b)* )? ]
161        }
162        $( $crate::if_atomic! { if $($rest)* } )?
163    };
164
165    ( if atomic(bool) $($rest:tt)* ) => {
166        $crate::if_atomic! { if atomic(8) $($rest)* }
167    };
168
169    ( if atomic(size) $($rest:tt)* ) => {
170        $crate::if_atomic! { if atomic(ptr) $($rest)* }
171    };
172
173    ( if ! atomic( $t:tt ) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
174        $crate::if_atomic! {
175            if atomic($t) { $( $($b)* )? } else { $($a)* } $( if $($rest)* )?
176        }
177    };
178}