riot_wrappers/
main_module.rs

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
//! Tools for providing a RIOT main function
//!
//! The main contribution of this module is the [`riot_main!`](super::riot_main!) macro.
//!
//! The alternative to using that (other than doing it manually) is to have C code along with the
//! Rust application that occupies the main function.
//!
//! In these cases, Rust code can be called into from the main C code by declaring the entry
//! functions `#[no_mangle] pub extern "C"`, and having analogous `extern` functions in the calling
//! C code.

use crate::stdio::println;
use crate::thread::{EndToken, StartToken};

// General alternative to this module: Build the extern "C" main all the time and request that the
// application implement a named function. I never got the main function to be carried to the
// linker step, though. If implemented like this, the module needs to be gated like
// set_panic_handler.
//
// extern "Rust" {
//     fn riot_main();
// }
//
// #[no_mangle]
// pub extern "C" fn main() -> u32 {
//     unsafe { riot_main() };
//     0
// }

use core::fmt;

mod sealed {
    pub trait Sealed<Variant> {}
}

use sealed::Sealed;

// The Variant argument is really just taking different types to allow "conflicting"
// implementations that are not conflicting but just ambiguous as long as nobody forces the Variant
// argument. Conveniently, that ambiguity is accepted.
//
// Thanks to Charles from #rust:matrix.org for pointing out this neat trick.
#[doc(hidden)]
pub trait UsableAsMain<Variant>: Sealed<Variant> {
    unsafe fn call_main(&self) -> i32;
}

// Beware that the following are *not* checked for being conflicting (because they are not), but if
// there were any situation of ambiguity, the main macro would break.

impl<F: Fn() -> T, T: Termination> Sealed<[u8; 1]> for F {}

impl<F: Fn() -> T, T: Termination> UsableAsMain<[u8; 1]> for F {
    unsafe fn call_main(&self) -> i32 {
        (self)().report()
    }
}

impl<F: Fn(StartToken) -> crate::never::Never> Sealed<[u8; 2]> for F {}

impl<F: Fn(StartToken) -> crate::never::Never> UsableAsMain<[u8; 2]> for F {
    unsafe fn call_main(&self) -> i32 {
        // unsafe: By construction of the C main function this only happens at startup time
        // with a thread that hasn't done anything relevant before.
        let unique = crate::thread::StartToken::new();

        (self)(unique)
    }
}

impl<F: Fn(StartToken) -> ((), EndToken)> Sealed<[u8; 3]> for F {}

impl<F: Fn(StartToken) -> ((), EndToken)> UsableAsMain<[u8; 3]> for F {
    unsafe fn call_main(&self) -> i32 {
        // unsafe: By construction of the C main function this only happens at startup time
        // with a thread that hasn't done anything relevant before.
        let unique = crate::thread::StartToken::new();

        // We're not really consuming the token, just require that the function can provide it and
        // doesn't just return without having invalidated all users of its PID
        let (termination, _token) = (self)(unique);
        termination.report()
    }
}

/// To have a nice Rust main function, run the `riot_main!` macro with the name of your main
/// function an item (ie. top level in a module) in your crate. The function identified by it must
/// return something that implements the Termination trait.
///
/// Example:
///
/// ```
/// # #![no_std]
/// # #![no_main]
/// use riot_wrappers::riot_main;
/// riot_main!(main);
///
/// fn main() {
///     unimplemented!()
/// }
/// ```
///
/// Functions with multiple signatures are accepted:
///
/// * `fn main()` -- useful for very simple programs
/// * `fn main() -> impl Termination` -- prints the error message according to the [Termination]
///   implementation (in particular, [Result] types with a [Debug] error are useful here)
/// * `fn main(tokens: StartToken) -> (impl Termination, EndToken)` -- this ensures that
///   the program has full control over the main thread. As a [StartToken] allows doing things that
///   require undoing before the thread may terminate (eg. subscribing it to messages), an
///   [EndToken] needs to be produced before the thread can terminate with a message as
///   above.
/// * `fn main(tokens: StartToken) -> !` -- a frequently useful variation thereof for main loops
///   that are loops anyway.
#[macro_export]
macro_rules! riot_main {
    ($main:ident) => {
        #[export_name = "main"]
        pub extern "C" fn c_main() -> i32 {
            unsafe { <_ as $crate::main::UsableAsMain<_>>::call_main(&$main) }
        }
    };
}

/// A result trait for main methods, analogous to std::process::Termination
pub trait Termination {
    fn report(self) -> i32;
}

impl Termination for () {
    fn report(self) -> i32 {
        0
    }
}

impl Termination for i32 {
    fn report(self) -> i32 {
        self
    }
}

// Copied and stripped down from std

impl<E: fmt::Debug> Termination for Result<(), E> {
    fn report(self) -> i32 {
        match self {
            Ok(()) => ().report(),
            Err(err) => Err::<crate::never::Never, _>(err).report(),
        }
    }
}

impl Termination for crate::never::Never {
    fn report(self) -> i32 {
        self
    }
}

impl Termination for core::convert::Infallible {
    fn report(self) -> i32 {
        match self {}
    }
}

impl<E: fmt::Debug> Termination for Result<crate::never::Never, E> {
    fn report(self) -> i32 {
        match self {
            Err(err) => {
                println!("Error: {:?}", err);
                1
            }
            #[allow(unreachable_patterns)] // reason: RIOT CI's stable is still 1.77
            Ok(never) => never,
        }
    }
}