11#![ doc = include_str ! ( "../README.md" ) ]
22#![ cfg_attr( not( any( doc, test) ) , no_std) ]
3+ // This only refuses unsafe code in functions/expressions in this crate, not ones generated by this
4+ // crate's macros.
35#![ cfg_attr( not( any( doc, test) ) , forbid( unsafe_code) ) ]
46//#[cfg(doc)]
57//extern crate alloc;
68
9+ /// Invoke am unsafe function.
710#[ macro_export]
8- macro_rules! unsafe_method {
9- ( $self: expr, $fn: expr $( , $arg: expr) + ) => {
10- } ;
11- }
12-
13- #[ macro_export]
14- macro_rules! unsafe_call {
15- ( $fn: expr $( , $arg: expr) + ) => {
16- // Enclosed in a block, so the result can be used as a value in an outer expression.
11+ macro_rules! unsafe_fn {
12+ ( $fn: expr $( , $arg: expr) + ) => {
13+ // Enclosed in a block, so that
14+ // 1. the result can be used as a value in an outer expression,and
15+ // 2. local variables don't conflict with the outer scope
1716 {
18- let tuple = $crate:: unsafe_call!{ ~ $( $arg) ,* } ;
19- unsafe {
20- $crate:: unsafe_call! { ~~
21- $fn,
22- tuple,
23- ( $( $arg ) ,* ) ,
24- ( 0 )
25- }
17+ let tuple = $crate:: unsafe_fn!{ ~~ $( $arg) ,* } ;
18+ let fun = $fn;
19+ $crate:: unsafe_fn! { ~~~
20+ fun,
21+ tuple,
22+ ( $( $arg ) ,* ) ,
23+ ( 0 )
2624 }
2725 }
2826 } ;
@@ -31,24 +29,26 @@ macro_rules! unsafe_call {
3129 } ;
3230
3331 // Construct the tuple:
34- ( ~ $first: expr, $( $rest: expr) ,+ ) => {
32+ ( ~~ $first: expr, $( $rest: expr) ,+ ) => {
3533 (
36- $first, $crate:: unsafe_call !{ ~ $( $rest) ,+ }
34+ $first, $crate:: unsafe_fn !{ ~ ~ $( $rest) ,+ }
3735 )
3836 } ;
39- ( ~ $last: expr) => {
37+ ( ~~ $last: expr) => {
4038 ( $last, )
4139 } ;
4240 // Commented out: For now, we require the (potentially unsafe) function to have at least 1 argument.
4341 //
44- //(~) => { () };
42+ //(~~ ) => { () };
4543
4644 // Access tuple parts and call the function:
47- ( ~~ $fn: expr, $tuple: ident,
45+ ( ~~~ $fn: expr, $tuple: ident,
4846 ( $_first_arg: expr, $( $other_arg: expr) ,+ ) ,
49- $( ( $( $accessor_part: tt) ,+ ) ) ,*
47+ $( ( $( $accessor_part: tt) ,+
48+ )
49+ ) ,*
5050 ) => {
51- $crate:: unsafe_call !{ ~~
51+ $crate:: unsafe_fn !{ ~ ~~
5252 $fn, $tuple, ( $( $other_arg) ,+ ) ,
5353 // Insert a new accessor to front (left): 0.
5454 ( 0 ) ,
@@ -57,23 +57,85 @@ macro_rules! unsafe_call {
5757 ) ,*
5858 }
5959 } ;
60- ( ~~ $fn: expr, $tuple: ident,
60+ // All accessors are ready, so call the function:
61+ ( ~~~ $fn: expr, $tuple: ident,
6162 ( $_last_or_only_arg: expr ) ,
6263 $( ( $( $accessor_part: tt) ,+
6364 )
6465 ) ,*
6566 ) => {
66- $fn( $(
67- $crate:: unsafe_call!{ ~~~ $tuple, $( $accessor_part) ,+ }
68- ) ,*
69- )
67+ unsafe {
68+ $fn( $(
69+ $crate:: unsafe_fn!{ ~~~~ $tuple, $( $accessor_part) ,+ }
70+ ) ,*
71+ )
72+ }
7073 } ;
7174
7275 // Expand an accessor group/list to access a field in the tuple:
73- ( ~~~ $tuple: ident, $( $accessor_part: tt) ,* ) => {
76+ ( ~~~~ $tuple: ident, $( $accessor_part: tt) ,* ) => {
7477 $tuple $( . $accessor_part ) *
7578 } ;
7679}
80+ //-------------
81+
82+ /// Invoke am unsafe method. Like [unsafe_fn], but
83+ /// - we accept a receiver `self`
84+ /// - we store `self` in a variable outside of the generated `unsafe {...}`
85+ /// - we don't allow $fn to be an expression (which doesn't work in standard methods calls), but
86+ /// only an identifier.
87+ #[ macro_export]
88+ macro_rules! unsafe_method {
89+ ( $self: expr, $fn: ident $( , $arg: expr) + ) => {
90+ // Enclosed in a block, so that
91+ // 1. the result can be used as a value in an outer expression,and
92+ // 2. local variables don't conflict with the outer scope
93+ {
94+ let tuple = $crate:: unsafe_fn!{ ~~ $( $arg) ,* } ; // re-using unsafe_fn
95+ let receiver = $self;
96+ $crate:: unsafe_method! { ~~~
97+ receiver,
98+ $fn,
99+ tuple,
100+ ( $( $arg ) ,* ) ,
101+ ( 0 )
102+ }
103+ }
104+ } ;
105+
106+ // Access tuple parts and call the function:
107+ ( ~~~ $self: expr, $fn: ident, $tuple: ident,
108+ ( $_first_arg: expr, $( $other_arg: expr) ,+ ) ,
109+ $( ( $( $accessor_part: tt) ,+
110+ )
111+ ) ,*
112+ ) => {
113+ $crate:: unsafe_method!{ ~~~
114+ $self, $fn, $tuple, ( $( $other_arg) ,+ ) ,
115+ // Insert a new accessor to front (left): 0.
116+ ( 0 ) ,
117+ $( // Prepend 1 to each supplied/existing accessor
118+ ( 1 , $( $accessor_part) ,+ )
119+ ) ,*
120+ }
121+ } ;
122+ // All accessors are ready, so call the function:
123+ ( ~~~ $self: expr, $fn: ident, $tuple: ident,
124+ ( $_last_or_only_arg: expr ) ,
125+ $( ( $( $accessor_part: tt) ,+
126+ )
127+ ) ,*
128+ ) => {
129+ unsafe {
130+ $self. $fn( $(
131+ $crate:: unsafe_fn!{ ~~~~ $tuple, $( $accessor_part) ,+ }
132+ ) ,*
133+ )
134+ }
135+ } ;
136+ }
137+
138+ //-------------
77139
78140#[ cfg( test) ]
79141mod tests {
@@ -83,16 +145,43 @@ mod tests {
83145
84146 #[ test]
85147 fn it_works ( ) {
86- //let tuple = unsafe_call!{ ~ 'c', true, 1, -5 };
87- unsafe_call ! ( unsafe_a, 'c' , true , 1 , -5 ) ;
148+ //let tuple = unsafe_fn!{~ ~ 'c', true, 1, -5 };
149+ unsafe_fn ! ( unsafe_a, 'c' , true , 1 , -5 ) ;
88150
89151 //unsafe fn f() {}
90- //unsafe_call !( f);
152+ //unsafe_fn !( f);
91153
92154 /*let args = ('c', (true, (1, (0,))));
93155 unsafe {
94156 let _ = unsafe_a(args.0, args.1.0, args.1.1.0, args.1.1.1.0);
95157 }
96158 */
159+
160+ let _ = unsafe_fn ! ( usize :: unchecked_add, 1 , 1 ) ;
161+ let _ = unsafe_method ! ( 1u8 , unchecked_add, 0 ) ;
162+ let _ = unsafe { 1_u8 . unchecked_add ( 0 ) } ;
163+ }
164+ }
165+
166+ // @TODO move to docs/tests
167+ #[ allow( unused) ]
168+ mod always_test {
169+ fn f ( i : usize ) -> usize {
170+ i + 1
171+ }
172+
173+ fn g ( ) -> fn ( usize ) -> usize {
174+ f
175+ }
176+
177+ pub fn store_function_name ( ) {
178+ let fun = f;
179+ f ( 0 ) ;
180+
181+ let fun = g;
182+ fun ( ) ( 1 ) ;
183+
184+ let fun = usize:: wrapping_add;
185+ fun ( 1 , 0 ) ;
97186 }
98187}
0 commit comments