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