@@ -28,6 +28,62 @@ use crate::stdio::println;
28
28
29
29
use core:: fmt;
30
30
31
+ mod sealed {
32
+ pub trait Sealed < Variant > { }
33
+ }
34
+
35
+ use sealed:: Sealed ;
36
+
37
+ // The Variant argument is really just taking different types to allow "conflicting"
38
+ // implementations that are not conflicting but just ambiguous as long as nobody forces the Variant
39
+ // argument. Conveniently, that ambiguity is accepted.
40
+ //
41
+ // Thanks to Charles from #rust:matrix.org for pointing out this neat trick.
42
+ #[ doc( hidden) ]
43
+ pub trait UsableAsMain < Variant > : Sealed < Variant > {
44
+ unsafe fn call_main ( & self ) -> i32 ;
45
+ }
46
+
47
+ // Beware that the following are *not* checked for being conflicting (because they are not), but if
48
+ // there were any situation of ambiguity, the main macro would break.
49
+
50
+ impl < F : Fn ( ) -> T , T : Termination > Sealed < [ u8 ; 1 ] > for F { }
51
+
52
+ impl < F : Fn ( ) -> T , T : Termination > UsableAsMain < [ u8 ; 1 ] > for F {
53
+ unsafe fn call_main ( & self ) -> i32 {
54
+ ( self ) ( ) . report ( )
55
+ }
56
+ }
57
+
58
+ impl < F : Fn ( crate :: thread:: StartToken ) -> crate :: never:: Never > Sealed < [ u8 ; 2 ] > for F { }
59
+
60
+ impl < F : Fn ( crate :: thread:: StartToken ) -> crate :: never:: Never > UsableAsMain < [ u8 ; 2 ] > for F {
61
+ unsafe fn call_main ( & self ) -> i32 {
62
+ // unsafe: By construction of the C main function this only happens at startup time
63
+ // with a thread that hasn't done anything relevant before.
64
+ let unique = crate :: thread:: StartToken :: new ( ) ;
65
+
66
+ ( self ) ( unique)
67
+ }
68
+ }
69
+
70
+ impl < F : Fn ( crate :: thread:: StartToken ) -> ( ( ) , crate :: thread:: EndToken ) > Sealed < [ u8 ; 3 ] > for F { }
71
+
72
+ impl < F : Fn ( crate :: thread:: StartToken ) -> ( ( ) , crate :: thread:: EndToken ) > UsableAsMain < [ u8 ; 3 ] >
73
+ for F
74
+ {
75
+ unsafe fn call_main ( & self ) -> i32 {
76
+ // unsafe: By construction of the C main function this only happens at startup time
77
+ // with a thread that hasn't done anything relevant before.
78
+ let unique = crate :: thread:: StartToken :: new ( ) ;
79
+
80
+ // We're not really consuming the token, just require that the function can provide it and
81
+ // doesn't just return without having invalidated all users of its PID
82
+ let ( termination, _token) = ( self ) ( unique) ;
83
+ termination. report ( )
84
+ }
85
+ }
86
+
31
87
/// To have a nice Rust main function, run the `riot_main!` macro with the name of your main
32
88
/// function an item (ie. top level in a module) in your crate. The function identified by it must
33
89
/// return something that implements the Termination trait.
@@ -43,29 +99,36 @@ use core::fmt;
43
99
/// unimplemented!()
44
100
/// }
45
101
/// ```
102
+ ///
103
+ /// Functions with multiple signatures are accepted:
104
+ ///
105
+ /// * `fn main()` -- useful for very simple programs
106
+ /// * `fn main() -> impl Termination` -- prints the error message according to the [Termination]
107
+ /// implementation (in particular, [Result] types with a [Debug] error are useful here)
108
+ /// * `fn main(tokens: StartToken) -> (impl Termination, EndToken)` -- this ensures that
109
+ /// the program has full control over the main thread. As a [StartToken] allows doing things that
110
+ /// require undoing before the thread may terminate (eg. subscribing it to messages), an
111
+ /// [EndToken] needs to be produced before the thread can terminate with a message as
112
+ /// above.
113
+ /// * `fn main(tokens: StartToken) -> !` -- a frequently useful variation thereof for main loops
114
+ /// that are loops anyway.
46
115
#[ macro_export]
47
116
macro_rules! riot_main {
48
117
( $main: ident) => {
49
118
#[ export_name = "main" ]
50
119
pub extern "C" fn c_main( ) -> i32 {
51
- use riot_wrappers:: main:: Termination ;
52
- $main( ) . report( )
120
+ unsafe { <_ as $crate:: main:: UsableAsMain <_>>:: call_main( & $main) }
53
121
}
54
122
} ;
55
123
}
56
124
125
+ #[ deprecated( note = "Use `riot_main` instead, which takes multiple signatures" ) ]
57
126
#[ macro_export]
58
127
macro_rules! riot_main_with_tokens {
59
128
( $main: ident) => {
60
129
#[ export_name = "main" ]
61
130
pub extern "C" fn c_main( ) -> i32 {
62
- // unsafe: By construction of the C main function this only happens at startup time
63
- // with a thread that hasn't done anything relevant before.
64
- let unique = unsafe { riot_wrappers:: thread:: StartToken :: new( ) } ;
65
-
66
- let ( result, token) : ( _, riot_wrappers:: thread:: TerminationToken ) = $main( unique) ;
67
- use riot_wrappers:: main:: Termination ;
68
- result. report( )
131
+ unsafe { <_ as $crate:: main:: UsableAsMain <_>>:: call_main( & $main) }
69
132
}
70
133
} ;
71
134
}
0 commit comments