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
//! Provides macros that allow downstream crates to examine the choice of
//! the target kernel.
//!
//! This module's macros whose names start with `tt_` follow `tt-call`'s token
//! tree calling convention.

include!(concat!(env!("OUT_DIR"), "/macros.rs"));

// Make `tt_call` available to the following macros' expansion
#[doc(hidden)]
pub use tt_call;

/// Expand to the current kernel's name (e.g., `"asp3"`).
///
/// # Examples
///
/// ```rust
/// println!("We are running on {}", itron::macros::kernel!());
/// ```
///
/// ```rust,compile_fail
/// compile_error!(concat!("kernel `", itron::macros::kernel!(), "` is not supported"));
/// ```
pub macro kernel() {
    tt_call::tt_call! { macro = [{ itron::macros::tt_kernel }] }
}

/// Expand to the arm corresponding to the current kernel.
///
/// # Example
///
/// ```rust
/// itron::macros::match_kernel! {
///     "asp3" | "solid_asp3" => { fn say() { println!("We are running on TOPPERS/ASP3, yay!"); } }
///     "nonexistent_kernel" => { call_nonexistent_function(); }
///     _ => { fn say() { println!("This kernel looks like something new!"); } }
/// }
/// say();
/// ```
///
/// The arms don't create local scopes, and unselected arms are eliminated
/// during an early stage of compilation. Compare to the following example:
///
/// ```rust,compile_fail
/// match itron::macros::kernel!() {
///     "asp3" | "solid_asp3" => { fn say() { println!("We are running on TOPPERS/ASP3, yay!"); } }
///     "nonexistent_kernel" => { call_nonexistent_function(); }
///         // ERROR: `call_nonexistent_function` is undefined
///     _ => { fn say() { println!("This kernel looks like something new!"); } }
/// }
/// say(); // ERROR: Each arm's `say` is not accessible from here
/// ```
///
pub macro match_kernel {
    (
        _ => { $($wildcard:tt)* }
    ) => { $($wildcard)* },
    (
        _ => { $($wildcard:tt)* }
        $($rest:tt)*
    ) => {
        compile_error!("anything that follow `_ => { ... }` never match")
    },
    (
        $( $kernel:tt )|+ => { $($tt:tt)* }
        $($rest:tt)*
    ) => {
        tt_call::tt_if! {
            condition = [{ $crate::macros::tt_is_kernel }]
            input = [{ $( $kernel )|+ }]
            true = [{ $($tt)* }]
            false = [{
                match_kernel! { $($rest)* }
            }]
        }
    },
}