11#![ no_std]
2+ #![ warn( clippy:: pedantic, clippy:: nursery) ]
3+ #![ deny( missing_docs) ]
4+ #![ deny( unsafe_code) ]
25#![ feature( unboxed_closures) ]
36#![ feature( fn_traits) ]
47#![ feature( const_trait_impl) ]
58#![ feature( const_mut_refs) ]
69#![ feature( const_refs_to_cell) ]
10+ #![ feature( const_ptr_read) ]
11+ #![ feature( const_option) ]
712
13+ /*!
14+ # Const Closure
15+ This crate allows using macros to automatically create closure like types/values.
16+
17+ This works by implementing the Fn* traits for a struct containing all the values captured form the environment.
18+
19+ Because of restrictions of declarative macros the used syntax is less than ideal, but it is a lot better than manual implementations of the Fn* traits.
20+
21+ For details of the Syntax see: `const_closure`.
22+
23+ # Example
24+ ```rust
25+ #![feature(unboxed_closures)]
26+ #![feature(fn_traits)]
27+ #![feature(const_trait_impl)]
28+ #![feature(const_mut_refs)]
29+ #![feature(const_refs_to_cell)]
30+ #![feature(const_ops)]
31+ use const_closure::const_closure;
32+
33+ const FROM_CLOSURE: i32 = {
34+ let base = 5;
35+ let calc = const_closure!([base: i32] (offset: i32) -> i32 {
36+ base + offset
37+ });
38+ calc(-2)
39+ };
40+ assert_eq!(FROM_CLOSURE, 3)
41+ ```
42+ !*/
43+
44+ /// # Macro for creating const callable "closures"
45+ ///
46+ /// The syntax is the following:
47+ ///
48+ /// const_closure!(`fn_type` for<`generics`> [`captures`] (`args`) -> `return_type` {`closure_body`})
49+ ///
50+ /// where:
51+ /// * `fn_type` is one of the Fn* traits (Fn, FnMut, FnOnce).
52+ /// * `generics` generics and bounds for them.
53+ /// * `captures` the list of arguments that the closure captures with function argument like typing.
54+ /// * `return_type` the return type of the closure.
55+ /// * `closure_body` the actual implementation of the closure.
56+ ///
57+ /// if `fn_type` is omitted it defaults to Fn.
58+ ///
59+ /// if no `generics` are required, the for<> can be omitted.
60+ ///
61+ /// if no `captures` are required, the [] can be omitted.
62+ ///
63+ /// if `return_type` is (), -> () can be omitted.
64+ ///
65+ /// #Advanced example:
66+ /// ```
67+ /// #![feature(unboxed_closures)]
68+ /// #![feature(fn_traits)]
69+ /// #![feature(const_trait_impl)]
70+ /// #![feature(const_mut_refs)]
71+ /// #![feature(const_refs_to_cell)]
72+ /// use const_closure::const_closure;
73+ /// use core::ops::Add;
74+ ///
75+ /// const fn add<T, G: Add<T, Output = G>>(l: G, r: T) -> G {
76+ /// let cl = const_closure!(FnOnce for<T, G: Add<T, Output = G>> [l: G, r: T] () -> G {
77+ /// l + r
78+ /// });
79+ /// cl()
80+ /// }
81+ /// assert_eq!(add(1, 5), 6);
82+ /// ```
83+ #[ cfg( doc) ]
84+ #[ macro_export]
85+ macro_rules! const_closure {
86+ ( $( $type: ident) ? $( for <$( $gen_name: ident $( : $( $trait_bound: path) * ) ?) ,* >) ? $this: ident $( [ $( $cap_name: ident : $cap_ty: ty ) ,+ $( , ) ?] ) ? ( $( $arg_name: ident: $arg_ty: ty) ,* ) $( -> $ret_ty: ty) ? { $( $body: tt) * } ) => { ... } ;
87+ }
88+
89+ #[ cfg( not( doc) ) ]
890#[ macro_export]
91+ #[ allow( missing_docs) ]
992macro_rules! const_closure {
1093 // Syntax sugar
1194 ( for $( $end: tt) * ) => { {
1295 const_closure!( Fn for $( $end) * )
1396 } } ;
14- ( $this : ident [ $( $mid: tt) * ] $( $end: tt) * ) => { {
15- const_closure!( Fn for <> $this [ $( $mid) * ] $( $end) * )
97+ ( [ $( $mid: tt) * ] $( $end: tt) * ) => { {
98+ const_closure!( Fn for <> [ $( $mid) * ] $( $end) * )
1699 } } ;
17- ( $this : ident ( $( $mid: tt) * ) $( $end: tt) * ) => { {
18- const_closure!( Fn for <> $this ( $( $mid) * ) $( $end) * )
100+ ( ( $( $mid: tt) * ) $( $end: tt) * ) => { {
101+ const_closure!( Fn for <> ( $( $mid) * ) $( $end) * )
19102 } } ;
20- ( $type: ident $this : ident [ $( $mid: tt) * ] $( $end: tt) * ) => { {
21- const_closure!( $type for <> $this [ $( $mid) * ] $( $end) * )
103+ ( $type: ident [ $( $mid: tt) * ] $( $end: tt) * ) => { {
104+ const_closure!( $type for <> [ $( $mid) * ] $( $end) * )
22105 } } ;
23- ( $type: ident for <$( $gen_name: ident $( : $( $trait_bound: path) * ) ?) ,* > $this : ident ( $( $mid: tt) * ) $( $end: tt) * ) => { {
24- const_closure!( $type for <$( $gen_name $( : $( $trait_bound) * ) ?) ,* > $this [ ] ( $( $mid) * ) $( $end) * )
106+ ( $type: ident for <$( $gen_name: ident $( : $( $trait_bound: path) * ) ?) ,* > ( $( $mid: tt) * ) $( $end: tt) * ) => { {
107+ const_closure!( $type for <$( $gen_name $( : $( $trait_bound) * ) ?) ,* > [ ] ( $( $mid) * ) $( $end) * )
25108 } } ;
26- ( $type: ident for <$( $gen_name: ident $( : $( $trait_bound: path) * ) ?) ,* > $this : ident [ $( $cap_name: ident : $cap_ty: ty ) ,* $( , ) ?] ( $( $arg_name: ident: $arg_ty: ty) ,* ) { $( $body: tt) * } ) => { {
27- const_closure!( $type for <$( $gen_name $( : $( $trait_bound) * ) ?) ,* > $this [ $( $cap_name : $cap_ty ) ,* ] ( $( $arg_name: $arg_ty) ,* ) -> ( ) { $( $body) * } )
109+ ( $type: ident for <$( $gen_name: ident $( : $( $trait_bound: path) * ) ?) ,* > [ $( $cap_name: ident : $cap_ty: ty ) ,* $( , ) ?] ( $( $arg_name: ident: $arg_ty: ty) ,* ) { $( $body: tt) * } ) => { {
110+ const_closure!( $type for <$( $gen_name $( : $( $trait_bound) * ) ?) ,* > [ $( $cap_name : $cap_ty ) ,* ] ( $( $arg_name: $arg_ty) ,* ) -> ( ) { $( $body) * } )
28111 } } ;
29112 // Actual Implementation
30- ( FnOnce for <$( $gen_name: ident $( : $( $trait_bound: path) * ) ?) ,* > $this : ident [ $( $cap_name: ident : $cap_ty: ty ) ,+ $( , ) ?] ( $( $arg_name: ident: $arg_ty: ty) ,* ) -> $ret_ty: ty { $( $body: tt) * } ) => { {
113+ ( FnOnce for <$( $gen_name: ident $( : $( $trait_bound: path) * ) ?) ,* > [ $( $cap_name: ident : $cap_ty: ty ) ,+ $( , ) ?] ( $( $arg_name: ident: $arg_ty: ty) ,* ) -> $ret_ty: ty { $( $body: tt) * } ) => { {
31114 #[ allow( non_snake_case) ]
32- struct Cl <$( $gen_name $( : $( $trait_bound) * ) ?) ,* > {
33- $( $gen_name: :: core:: marker:: PhantomData <* const $gen_name>) , *
115+ struct Cl <$( $gen_name $( : $( $trait_bound) * ) ?) ,* >{
116+ $( $gen_name: :: core:: marker:: PhantomData <* const $gen_name>, ) *
34117 $( $cap_name: $cap_ty) ,*
35118 }
36- impl <$( $gen_name $( : $( ~const $trait_bound + ) + ~const :: core:: marker:: Destruct ) ?) ,* > const FnOnce <( $( $arg_ty, ) * ) > for Cl <$( $gen_name) ,* > {
119+ impl <$( $gen_name $( : $( ~const $trait_bound + ) + ~const :: core:: marker:: Destruct ) ?) ,* > const FnOnce <( $( $arg_ty, ) * ) > for Cl <$( $gen_name) ,* >
120+ where Self : ~const :: core:: marker:: Destruct {
37121 type Output = $ret_ty;
38122
39123 #[ allow( unused_parens) ]
40124 extern "rust-call" fn call_once( self , ( $( $arg_name, ) * ) : ( $( $arg_ty, ) * ) ) -> Self :: Output {
41- #[ allow( unused_mut) ]
42- #[ allow( unused_variables) ]
43- let mut $this = self ;
125+ $(
126+ #[ allow( unused_mut) ]
127+ #[ allow( unused_variables) ]
128+ let mut $cap_name = self . $cap_name;
129+ ) *
44130 $( $body) *
45131 }
46132 }
47133 Cl {
48- $( $gen_name: :: core:: marker:: PhantomData ) , *
49- $( $cap_name: $cap_name ) ,*
134+ $( $gen_name: :: core:: marker:: PhantomData , ) *
135+ $( $cap_name) ,*
50136 }
51137 } } ;
52- ( FnMut for <$( $gen_name: ident $( : $( $trait_bound: path) * ) ?) ,* > $this : ident [ $( $cap_name: ident : $cap_ty: ty) ,* $( , ) ?] ( $( $arg_name: ident: $arg_ty: ty) ,* ) -> $ret_ty: ty { $( $body: tt) * } ) => { {
138+ ( FnMut for <$( $gen_name: ident $( : $( $trait_bound: path) * ) ?) ,* > [ $( $cap_name: ident : $cap_ty: ty) ,* $( , ) ?] ( $( $arg_name: ident: $arg_ty: ty) ,* ) -> $ret_ty: ty { $( $body: tt) * } ) => { {
53139 #[ allow( non_snake_case) ]
54140 struct Cl <' a, $( $gen_name $( : $( $trait_bound) * ) ?) ,* > {
55141 _lt: :: core:: marker:: PhantomData <& ' a mut u8 >,
56- $( $gen_name: :: core:: marker:: PhantomData <* const $gen_name>) , *
57- $( $cap_name: & ' a mut $cap_ty) , *
142+ $( $gen_name: :: core:: marker:: PhantomData <* const $gen_name>, ) *
143+ $( $cap_name: Option < & ' a mut $cap_ty> , ) *
58144 }
59145 impl <' a, $( $gen_name $( : $( ~const $trait_bound + ) + ~const :: core:: marker:: Destruct ) ?) ,* > const FnOnce <( $( $arg_ty, ) * ) > for Cl <' a, $( $gen_name) ,* > {
60146 type Output = $ret_ty;
@@ -64,27 +150,30 @@ macro_rules! const_closure {
64150 self . call_mut( args)
65151 }
66152 }
153+
67154 impl <' a, $( $gen_name $( : $( ~const $trait_bound + ) + ~const :: core:: marker:: Destruct ) ?) ,* > const FnMut <( $( $arg_ty, ) * ) > for Cl <' a, $( $gen_name) ,* > {
68155
69156 #[ allow( unused_parens) ]
70157 extern "rust-call" fn call_mut( & mut self , ( $( $arg_name, ) * ) : ( $( $arg_ty, ) * ) ) -> Self :: Output {
71- #[ allow( unused_variables) ]
72- let $this = self ;
73- $( $body) *
158+ // Hack to extract the references from Self
159+ $( let $cap_name = self . $cap_name. take( ) . unwrap( ) ; ) *
160+ let ret = { $( $body) * } ;
161+ $( self . $cap_name = Some ( $cap_name) ; ) *
162+ ret
74163 }
75164 }
76165 Cl {
77166 _lt: :: core:: marker:: PhantomData ,
78- $( $gen_name: :: core:: marker:: PhantomData ) , *
79- $( $cap_name: & mut $cap_name) ,*
167+ $( $gen_name: :: core:: marker:: PhantomData , ) *
168+ $( $cap_name: Some ( & mut $cap_name) , ) *
80169 }
81170 } } ;
82- ( Fn for <$( $gen_name: ident $( : $( $trait_bound: path) * ) ?) ,* > $this : ident [ $( $cap_name: ident : $cap_ty: ty ) ,* $( , ) ?] ( $( $arg_name: ident: $arg_ty: ty) ,* ) -> $ret_ty: ty { $( $body: tt) * } ) => { {
171+ ( Fn for <$( $gen_name: ident $( : $( $trait_bound: path) * ) ?) ,* > [ $( $cap_name: ident : $cap_ty: ty ) ,* $( , ) ?] ( $( $arg_name: ident: $arg_ty: ty) ,* ) -> $ret_ty: ty { $( $body: tt) * } ) => { {
83172 #[ allow( non_snake_case) ]
84173 struct Cl <' a, $( $gen_name $( : $( $trait_bound) * ) ?) ,* > {
85174 _lt: :: core:: marker:: PhantomData <& ' a u8 >,
86- $( $gen_name: :: core:: marker:: PhantomData <* const $gen_name>) , *
87- $( $cap_name: & ' a $cap_ty) , *
175+ $( $gen_name: :: core:: marker:: PhantomData <* const $gen_name>, ) *
176+ $( $cap_name: & ' a $cap_ty, ) *
88177 }
89178 impl <' a, $( $gen_name $( : $( ~const $trait_bound + ) + ~const :: core:: marker:: Destruct ) ?) ,* > const FnOnce <( $( $arg_ty, ) * ) > for Cl <' a, $( $gen_name) ,* > {
90179 type Output = $ret_ty;
@@ -102,15 +191,17 @@ macro_rules! const_closure {
102191
103192 #[ allow( unused_parens) ]
104193 extern "rust-call" fn call( & self , ( $( $arg_name, ) * ) : ( $( $arg_ty, ) * ) ) -> Self :: Output {
105- #[ allow( unused_variables) ]
106- let $this = self ;
194+ $(
195+ #[ allow( unused_variables) ]
196+ let $cap_name = self . $cap_name;
197+ ) *
107198 $( $body) *
108199 }
109200 }
110201 Cl {
111202 _lt: :: core:: marker:: PhantomData ,
112- $( $gen_name: :: core:: marker:: PhantomData ) , *
113- $( $cap_name: & mut $cap_name) , *
203+ $( $gen_name: :: core:: marker:: PhantomData , ) *
204+ $( $cap_name: & $cap_name, ) *
114205 }
115206 } } ;
116207}
0 commit comments