44#![ allow( private_bounds) ]
55
66use std:: any:: { Any , TypeId } ;
7+ use std:: cell:: { RefCell , UnsafeCell } ;
78use std:: rc:: Rc ;
89
9- use crate :: fn_ptr_arg:: { ArgList , ArgRepr , FnPtrArg , FnPtrArgs } ;
10- use crate :: rc:: Ptr ;
10+ use crate :: fn_ptr_arg:: { ArgList , ArgRepr , FnPtrArg , FnPtrArgs , record_from_repr } ;
11+ use crate :: rc:: { AsPointer , Ptr } ;
1112use crate :: reinterpret:: ByteRepr ;
1213use crate :: void:: { AnyPtr , ErasedPtr } ;
1314
@@ -70,6 +71,7 @@ pub struct FnPtr<T: FnSig> {
7071 // The function this pointer was created from, kept type-erased (but
7172 // still callable, through `Adapted`).
7273 original : Option < Rc < dyn Adapted > > ,
74+ lambda : Option < Rc < dyn Fn ( T :: Args ) -> T :: Ret > > ,
7375}
7476
7577impl < T : FnSig > FnPtr < T > {
@@ -79,6 +81,7 @@ impl<T: FnSig> FnPtr<T> {
7981 addr : 0 ,
8082 current : None ,
8183 original : None ,
84+ lambda : None ,
8285 }
8386 }
8487
@@ -93,6 +96,7 @@ impl<T: FnSig> FnPtr<T> {
9396 addr : f. fn_addr ( ) ,
9497 current : Some ( f) ,
9598 original : None ,
99+ lambda : None ,
96100 }
97101 }
98102
@@ -103,6 +107,9 @@ impl<T: FnSig> FnPtr<T> {
103107 if self . is_null ( ) {
104108 panic ! ( "ub: null fn pointer call" ) ;
105109 }
110+ if let Some ( lambda) = & self . lambda {
111+ return lambda ( args) ;
112+ }
106113 if let Some ( f) = self . current {
107114 return f. call_direct ( args) ;
108115 }
@@ -145,10 +152,17 @@ impl<T: FnSig> FnPtr<T> {
145152 self . boxed_original ( )
146153 } ;
147154
155+ let lambda: & dyn Any = & self . lambda ;
156+ let lambda = lambda
157+ . downcast_ref :: < Option < Rc < dyn Fn ( U :: Args ) -> U :: Ret > > > ( )
158+ . cloned ( )
159+ . flatten ( ) ;
160+
148161 FnPtr {
149162 addr : self . addr ,
150163 current : current_as_u. or ( original_as_u) ,
151164 original,
165+ lambda,
152166 }
153167 }
154168
@@ -175,6 +189,38 @@ macro_rules! impl_fn_ptr_call {
175189 pub fn call( & self $( , $a: $a) * ) -> R {
176190 self . call_args( ( $( $a, ) * ) )
177191 }
192+
193+ #[ allow( non_snake_case) ]
194+ pub fn with_captures<Captures : ' static >(
195+ captures: Captures ,
196+ body: fn ( Ptr <Captures > $( , $a) * ) -> R ,
197+ ) -> Self {
198+ let captures = Rc :: new( RefCell :: new( captures) ) ;
199+ FnPtr {
200+ addr: body as usize ,
201+ current: None ,
202+ original: None ,
203+ lambda: Some ( Rc :: new( move |( $( $a, ) * ) : ( $( $a, ) * ) | {
204+ body( captures. as_pointer( ) $( , $a) * )
205+ } ) ) ,
206+ }
207+ }
208+
209+ #[ allow( non_snake_case) ]
210+ pub fn with_captures_unsafe<Captures : ' static >(
211+ captures: Captures ,
212+ body: fn ( & mut Captures $( , $a) * ) -> R ,
213+ ) -> Self {
214+ let captures = Rc :: new( UnsafeCell :: new( captures) ) ;
215+ FnPtr {
216+ addr: body as usize ,
217+ current: None ,
218+ original: None ,
219+ lambda: Some ( Rc :: new( move |( $( $a, ) * ) : ( $( $a, ) * ) | {
220+ body( unsafe { & mut * captures. get( ) } $( , $a) * )
221+ } ) ) ,
222+ }
223+ }
178224 }
179225 impl_fn_ptr_call!( @peel $( $a) * ) ;
180226 } ;
@@ -191,6 +237,7 @@ impl<T: FnSig> Clone for FnPtr<T> {
191237 addr : self . addr ,
192238 current : self . current ,
193239 original : self . original . clone ( ) ,
240+ lambda : self . lambda . clone ( ) ,
194241 }
195242 }
196243}
@@ -211,6 +258,16 @@ impl<T: FnSig> Eq for FnPtr<T> {}
211258
212259impl < T : FnSig > ByteRepr for FnPtr < T > { }
213260
261+ impl < T : FnSig > FnPtrArg for FnPtr < T > {
262+ #[ inline]
263+ fn to_repr ( & self ) -> ArgRepr < ' _ > {
264+ ArgRepr :: Record ( self )
265+ }
266+ fn from_repr ( r : & ArgRepr ) -> Self {
267+ record_from_repr ( r)
268+ }
269+ }
270+
214271impl < T : FnSig > ErasedPtr for FnPtr < T > {
215272 fn as_bytes ( & self ) -> Ptr < u8 > {
216273 panic ! ( "byte view not supported on fn pointer" ) ;
0 commit comments