1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#[doc(hidden)]
#[macro_export]
#[cfg(radium_atomic_8)]
macro_rules! __radium_if_atomic_8 {
    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
}

#[doc(hidden)]
#[macro_export]
#[cfg(not(radium_atomic_8))]
macro_rules! __radium_if_atomic_8 {
    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
}

#[doc(hidden)]
#[macro_export]
#[cfg(radium_atomic_16)]
macro_rules! __radium_if_atomic_16 {
    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
}

#[doc(hidden)]
#[macro_export]
#[cfg(not(radium_atomic_16))]
macro_rules! __radium_if_atomic_16 {
    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
}

#[doc(hidden)]
#[macro_export]
#[cfg(radium_atomic_32)]
macro_rules! __radium_if_atomic_32 {
    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
}

#[doc(hidden)]
#[macro_export]
#[cfg(not(radium_atomic_32))]
macro_rules! __radium_if_atomic_32 {
    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
}

#[doc(hidden)]
#[macro_export]
#[cfg(radium_atomic_64)]
macro_rules! __radium_if_atomic_64 {
    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
}

#[doc(hidden)]
#[macro_export]
#[cfg(not(radium_atomic_64))]
macro_rules! __radium_if_atomic_64 {
    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
}

#[doc(hidden)]
#[macro_export]
#[cfg(radium_atomic_ptr)]
macro_rules! __radium_if_atomic_ptr {
    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
}

#[doc(hidden)]
#[macro_export]
#[cfg(not(radium_atomic_ptr))]
macro_rules! __radium_if_atomic_ptr {
    ( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
}

/// Conditional compilation based on the presence of atomic instructions.
///
/// This macro allows you to write `if`/`else` clauses, evaluated at
/// compile-time, that test the presence of atomic instructions and preserve or
/// destroy their guarded code accordingly.
///
/// The `if atomic(WIDTH)` test preserves the contents of its block when the
/// target architecture has atomic instructions for the requested `WIDTH`, and
/// removes them from the syntax tree when the target does not. If an `else`
/// clause is provided, the contents of the `else` block are used as a
/// substitute when the `if` is destroyed.
///
/// This macro can be used in any position. When it is used in item or statement
/// position, it can contain multiple `if` clauses, and each will be evaluated
/// in turn. Expression and type positions can only accept exactly one code
/// span, and so may only have exactly one `if`/`else` clause. An `else` clause
/// is required here so that the macro will always expand to something; an empty
/// expansion is a parse error.
///
/// # Macro Syntax
///
/// The macro contents `if atomic() {} else {}` are part of the macro
/// invocation. Only the contents of the two blocks are actual Rust code.
///
/// The acceptable arguments to `atomic()` are:
///
/// - `8`
/// - `16`
/// - `32`
/// - `64`
/// - `ptr`
/// - `bool`: alias for `8`
/// - `size`: alias for `ptr`
///
/// In addition, the `atomic()` test can be inverted, as `!atomic()`, to reverse
/// the preserve/destroy behavior of the `if` and `else` blocks.
///
/// # Examples
///
/// This demonstrates the use of `if_atomic!` to produce multiple statements,
/// and then to produce a single type-name.
///
/// ```rust
/// radium::if_atomic! {
///   if atomic(size) { use core::sync::atomic::AtomicUsize; }
///   if !atomic(size) { use core::cell::Cell; }
/// }
///
/// struct RadiumRc<T: ?Sized> {
///   strong: radium::if_atomic! {
///     if atomic(ptr) { AtomicUsize }
///     else { Cell<usize> }
///   },
///   weak: radium::types::RadiumUsize,
///   data: T,
/// }
/// ```
#[macro_export]
macro_rules! if_atomic {
    ( if atomic(8) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
        $crate::__radium_if_atomic_8! {
            [ $($a)* ] [ $( $($b)* )? ]
        }
        $($crate::if_atomic! { if $($rest)* })?
    };

    ( if atomic(16) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
        $crate::__radium_if_atomic_16! {
            [ $($a)* ] [ $( $($b)* )? ]
        }
        $( $crate::if_atomic! { if $($rest)* } )?
    };

    ( if atomic(32) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
        $crate::__radium_if_atomic_32! {
            [ $($a)* ] [ $( $($b)* )? ]
        }
        $( $crate::if_atomic! { if $($rest)* } )?
    };

    ( if atomic(64) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
        $crate::__radium_if_atomic_64! {
            [ $($a)* ] [ $( $($b)* )? ]
        }
        $( $crate::if_atomic! { if $($rest)* } )?
    };

    ( if atomic(ptr) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
        $crate::__radium_if_atomic_ptr! {
            [ $($a)* ] [ $( $($b)* )? ]
        }
        $( $crate::if_atomic! { if $($rest)* } )?
    };

    ( if atomic(bool) $($rest:tt)* ) => {
        $crate::if_atomic! { if atomic(8) $($rest)* }
    };

    ( if atomic(size) $($rest:tt)* ) => {
        $crate::if_atomic! { if atomic(ptr) $($rest)* }
    };

    ( if ! atomic( $t:tt ) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
        $crate::if_atomic! {
            if atomic($t) { $( $($b)* )? } else { $($a)* } $( if $($rest)* )?
        }
    };
}