sysinfo/
macros.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3#[cfg(feature = "debug")]
4#[doc(hidden)]
5#[allow(unused)]
6macro_rules! sysinfo_debug {
7    ($($x:tt)*) => {{
8        eprintln!($($x)*);
9    }}
10}
11
12#[cfg(not(feature = "debug"))]
13#[doc(hidden)]
14#[allow(unused)]
15macro_rules! sysinfo_debug {
16    ($($x:tt)*) => {{}};
17}
18
19#[cfg(feature = "system")]
20macro_rules! declare_signals {
21    ($kind:ty, _ => None,) => (
22        use crate::Signal;
23
24        pub(crate) const fn supported_signals() -> &'static [Signal] {
25            &[]
26        }
27    );
28
29    ($kind:ty, $(Signal::$signal:ident => $map:expr,)+ _ => None,) => (
30        use crate::Signal;
31
32        pub(crate) const fn supported_signals() -> &'static [Signal] {
33            &[$(Signal::$signal,)*]
34        }
35
36        #[inline]
37        pub(crate) fn convert_signal(s: Signal) -> Option<$kind> {
38            match s {
39                $(Signal::$signal => Some($map),)*
40                _ => None,
41            }
42        }
43    );
44
45    ($kind:ty, $(Signal::$signal:ident => $map:expr,)+) => (
46        use crate::Signal;
47
48        pub(crate) const fn supported_signals() -> &'static [Signal] {
49            &[$(Signal::$signal,)*]
50        }
51
52        #[inline]
53        pub(crate) fn convert_signal(s: Signal) -> Option<$kind> {
54            match s {
55                $(Signal::$signal => Some($map),)*
56            }
57        }
58    )
59}
60
61#[cfg(all(unix, not(feature = "unknown-ci")))]
62#[allow(unused_macros)]
63macro_rules! retry_eintr {
64    (set_to_0 => $($t:tt)+) => {{
65        #[allow(unused_unsafe)]
66        let errno = unsafe { crate::unix::libc_errno() };
67        if !errno.is_null() {
68            #[allow(unused_unsafe)]
69            unsafe { *errno = 0; }
70        }
71        retry_eintr!($($t)+)
72    }};
73    ($errno_value:ident => $($t:tt)+) => {{
74        loop {
75            let ret = $($t)+;
76            if ret < 0 {
77                let tmp = std::io::Error::last_os_error();
78                if tmp.kind() == std::io::ErrorKind::Interrupted {
79                    continue;
80                }
81                $errno_value = tmp.raw_os_error().unwrap_or(0);
82            }
83            break ret;
84        }
85    }};
86    ($($t:tt)+) => {{
87        loop {
88            let ret = $($t)+;
89            if ret < 0 && std::io::Error::last_os_error().kind() == std::io::ErrorKind::Interrupted {
90                continue;
91            }
92            break ret;
93        }
94    }};
95}
96
97//FIXME: Remove this code if https://github.com/rust-lang/cfg-if/pull/78 is ever merged.
98macro_rules! cfg_if {
99    // match if/else chains with a final `else`
100    (
101        $(
102            if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* }
103        ) else+
104        else { $( $e_tokens:tt )* }
105    ) => {
106        cfg_if! {
107            @__items () ;
108            $(
109                (( $i_meta ) ( $( $i_tokens )* )) ,
110            )+
111            (() ( $( $e_tokens )* )) ,
112        }
113    };
114
115    // Allow to multiple conditions in a same call.
116    (
117        $(
118            if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* }
119        ) else+
120        else { $( $e_tokens:tt )* }
121        if $($extra_conditions:tt)+
122    ) => {
123        cfg_if! {
124            @__items () ;
125            $(
126                (( $i_meta ) ( $( $i_tokens )* )) ,
127            )+
128            (() ( $( $e_tokens )* )) ,
129        }
130        cfg_if! {
131            if $($extra_conditions)+
132        }
133    };
134
135    // match if/else chains lacking a final `else`
136    (
137        if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* }
138        $(
139            else if #[cfg( $e_meta:meta )] { $( $e_tokens:tt )* }
140        )*
141    ) => {
142        cfg_if! {
143            @__items () ;
144            (( $i_meta ) ( $( $i_tokens )* )) ,
145            $(
146                (( $e_meta ) ( $( $e_tokens )* )) ,
147            )*
148        }
149    };
150
151    // Allow to multiple conditions in a same call.
152    (
153        if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* }
154        $(
155            else if #[cfg( $e_meta:meta )] { $( $e_tokens:tt )* }
156        )*
157        if $($extra_conditions:tt)+
158    ) => {
159        cfg_if! {
160            @__items () ;
161            (( $i_meta ) ( $( $i_tokens )* )) ,
162            $(
163                (( $e_meta ) ( $( $e_tokens )* )) ,
164            )*
165        }
166        cfg_if! {
167            if $($extra_conditions)+
168        }
169    };
170
171    // Internal and recursive macro to emit all the items
172    //
173    // Collects all the previous cfgs in a list at the beginning, so they can be
174    // negated. After the semicolon is all the remaining items.
175    (@__items ( $( $_:meta , )* ) ; ) => {};
176    (
177        @__items ( $( $no:meta , )* ) ;
178        (( $( $yes:meta )? ) ( $( $tokens:tt )* )) ,
179        $( $rest:tt , )*
180    ) => {
181        // Emit all items within one block, applying an appropriate #[cfg]. The
182        // #[cfg] will require all `$yes` matchers specified and must also negate
183        // all previous matchers.
184        #[cfg(all(
185            $( $yes , )?
186            not(any( $( $no ),* ))
187        ))]
188        cfg_if! { @__identity $( $tokens )* }
189
190        // Recurse to emit all other items in `$rest`, and when we do so add all
191        // our `$yes` matchers to the list of `$no` matchers as future emissions
192        // will have to negate everything we just matched as well.
193        cfg_if! {
194            @__items ( $( $no , )* $( $yes , )? ) ;
195            $( $rest , )*
196        }
197    };
198
199    // Internal macro to make __apply work out right for different match types,
200    // because of how macros match/expand stuff.
201    (@__identity $( $tokens:tt )* ) => {
202        $( $tokens )*
203    };
204}
205
206#[cfg(test)]
207#[allow(unexpected_cfgs)]
208mod tests {
209    cfg_if! {
210        if #[cfg(test)] {
211            use core::option::Option as Option2;
212            fn works1() -> Option2<u32> { Some(1) }
213        } else {
214            fn works1() -> Option<u32> { None }
215        }
216    }
217
218    cfg_if! {
219        if #[cfg(foo)] {
220            fn works2() -> bool { false }
221        } else if #[cfg(test)] {
222            fn works2() -> bool { true }
223        } else {
224            fn works2() -> bool { false }
225        }
226    }
227
228    cfg_if! {
229        if #[cfg(foo)] {
230            fn works3() -> bool { false }
231        } else {
232            fn works3() -> bool { true }
233        }
234    }
235
236    cfg_if! {
237        if #[cfg(test)] {
238            use core::option::Option as Option3;
239            fn works4() -> Option3<u32> { Some(1) }
240        }
241    }
242
243    cfg_if! {
244        if #[cfg(foo)] {
245            fn works5() -> bool { false }
246        } else if #[cfg(test)] {
247            fn works5() -> bool { true }
248        }
249    }
250
251    cfg_if! {
252        if #[cfg(foo)] {
253            fn works6() -> bool { false }
254        } else if #[cfg(test)] {
255            fn works6() -> bool { true }
256        }
257        if #[cfg(test)] {
258            fn works7() -> bool { true }
259        } else {
260            fn works7() -> bool { false }
261        }
262    }
263
264    cfg_if! {
265        if #[cfg(test)] {
266            fn works8() -> bool { true }
267        } else if #[cfg(foo)] {
268            fn works8() -> bool { false }
269        }
270        if #[cfg(foo)] {
271            fn works9() -> bool { false }
272        } else if #[cfg(test)] {
273            fn works9() -> bool { true }
274        }
275    }
276
277    #[test]
278    fn it_works() {
279        assert!(works1().is_some());
280        assert!(works2());
281        assert!(works3());
282        assert!(works4().is_some());
283        assert!(works5());
284        assert!(works6());
285        assert!(works7());
286        assert!(works8());
287        assert!(works9());
288    }
289
290    #[test]
291    #[allow(clippy::assertions_on_constants)]
292    fn test_usage_within_a_function() {
293        cfg_if! {if #[cfg(debug_assertions)] {
294            // we want to put more than one thing here to make sure that they
295            // all get configured properly.
296            assert!(cfg!(debug_assertions));
297            assert_eq!(4, 2+2);
298        } else {
299            assert!(works1().is_some());
300            assert_eq!(10, 5+5);
301        }}
302    }
303
304    #[allow(dead_code)]
305    trait Trait {
306        fn blah(&self);
307    }
308
309    #[allow(dead_code)]
310    struct Struct;
311
312    impl Trait for Struct {
313        cfg_if! {
314            if #[cfg(feature = "blah")] {
315                fn blah(&self) {
316                    unimplemented!();
317                }
318            } else {
319                fn blah(&self) {
320                    unimplemented!();
321                }
322            }
323        }
324    }
325}