@@ -41,6 +41,24 @@ enum WrapperParamKind {
4141 SliceArgs ,
4242}
4343
44+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
45+ pub ( crate ) enum HostBindingKind {
46+ StaticStack ,
47+ StaticArgs ,
48+ StaticNonYieldingArgs ,
49+ }
50+
51+ impl HostBindingKind {
52+ pub ( crate ) fn render_bind_static_call ( & self , name : & str , function_name : & str ) -> String {
53+ let method = match self {
54+ Self :: StaticStack => "bind_static_stack_function" ,
55+ Self :: StaticNonYieldingArgs => "bind_static_non_yielding_args_function" ,
56+ Self :: StaticArgs => "bind_static_args_function" ,
57+ } ;
58+ format ! ( "vm.{method}({name:?}, {function_name});" )
59+ }
60+ }
61+
4462#[ derive( Clone , Debug ) ]
4563struct CallableDecl {
4664 rust_ident : String ,
@@ -51,6 +69,7 @@ struct CallableDecl {
5169 return_label : String ,
5270 static_return_type : String ,
5371 wrapper : Option < WrapperDecl > ,
72+ host_binding_kind : HostBindingKind ,
5473}
5574
5675#[ derive( Clone , Debug ) ]
@@ -184,6 +203,110 @@ fn parse_sources(
184203 out
185204}
186205
206+ pub ( crate ) fn classify_host_binding ( function : & ItemFn ) -> HostBindingKind {
207+ if function. sig . inputs . iter ( ) . any ( |input| match input {
208+ FnArg :: Typed ( pat_type) => is_vm_context_type ( & pat_type. ty ) ,
209+ _ => false ,
210+ } ) {
211+ return HostBindingKind :: StaticStack ;
212+ }
213+ let return_type = normalized_return_type ( & function. sig . output ) ;
214+ if matches ! (
215+ plain_path_type( & return_type) . as_deref( ) ,
216+ Some ( "CallOutcome" )
217+ ) {
218+ return HostBindingKind :: StaticArgs ;
219+ }
220+ if let Some ( inner) = sole_type_argument ( & return_type, "VmResult" )
221+ . or_else ( || sole_type_argument ( & return_type, "HostResult" ) )
222+ {
223+ if matches ! ( plain_path_type( & inner) . as_deref( ) , Some ( "CallOutcome" ) ) {
224+ return HostBindingKind :: StaticArgs ;
225+ }
226+ }
227+ if is_supported_ordinary_return_type ( & return_type) {
228+ return HostBindingKind :: StaticNonYieldingArgs ;
229+ }
230+ HostBindingKind :: StaticArgs
231+ }
232+
233+ fn is_supported_ordinary_return_type ( ty : & Type ) -> bool {
234+ match ty {
235+ Type :: Group ( group) => is_supported_ordinary_return_type ( & group. elem ) ,
236+ Type :: Paren ( paren) => is_supported_ordinary_return_type ( & paren. elem ) ,
237+ Type :: Reference ( reference) => is_supported_ordinary_return_type ( & reference. elem ) ,
238+ Type :: Path ( path) => {
239+ path. path
240+ . segments
241+ . last ( )
242+ . is_some_and ( |seg| match seg. ident . to_string ( ) . as_str ( ) {
243+ "Option" | "VmResult" | "HostResult" => {
244+ let syn:: PathArguments :: AngleBracketed ( args) = & seg. arguments else {
245+ return false ;
246+ } ;
247+ args. args
248+ . first ( )
249+ . and_then ( |arg| match arg {
250+ syn:: GenericArgument :: Type ( inner) => Some ( inner) ,
251+ _ => None ,
252+ } )
253+ . is_some_and ( |inner| is_supported_ordinary_return_type ( inner) )
254+ }
255+ _ => true ,
256+ } )
257+ }
258+ Type :: Tuple ( tuple) => tuple. elems . is_empty ( ) ,
259+ _ => false ,
260+ }
261+ }
262+
263+ fn normalized_return_type ( output : & ReturnType ) -> Type {
264+ match output {
265+ ReturnType :: Default => syn:: parse_quote!( ( ) ) ,
266+ ReturnType :: Type ( _, ty) => unwrap_surface_type ( ty) ,
267+ }
268+ }
269+
270+ fn unwrap_surface_type ( ty : & Type ) -> Type {
271+ match ty {
272+ Type :: Group ( group) => unwrap_surface_type ( & group. elem ) ,
273+ Type :: Paren ( paren) => unwrap_surface_type ( & paren. elem ) ,
274+ Type :: Reference ( reference) => unwrap_surface_type ( & reference. elem ) ,
275+ _ => ty. clone ( ) ,
276+ }
277+ }
278+
279+ fn plain_path_type ( ty : & Type ) -> Option < String > {
280+ match ty {
281+ Type :: Group ( group) => plain_path_type ( & group. elem ) ,
282+ Type :: Paren ( paren) => plain_path_type ( & paren. elem ) ,
283+ Type :: Reference ( reference) => plain_path_type ( & reference. elem ) ,
284+ Type :: Path ( path) => path. path . segments . last ( ) . map ( |seg| seg. ident . to_string ( ) ) ,
285+ _ => None ,
286+ }
287+ }
288+
289+ fn sole_type_argument ( ty : & Type , wrapper : & str ) -> Option < Type > {
290+ let ty = unwrap_surface_type ( ty) ;
291+ match & ty {
292+ Type :: Path ( path) => {
293+ let segment = path. path . segments . last ( ) ?;
294+ if segment. ident != wrapper {
295+ return None ;
296+ }
297+ let syn:: PathArguments :: AngleBracketed ( args) = & segment. arguments else {
298+ return None ;
299+ } ;
300+ let arg = args. args . first ( ) ?;
301+ match arg {
302+ syn:: GenericArgument :: Type ( inner) => Some ( inner. clone ( ) ) ,
303+ _ => None ,
304+ }
305+ }
306+ _ => None ,
307+ }
308+ }
309+
187310fn parse_source_file ( path : & Path , spec : & SourceSpec , _order_offset : usize ) -> Vec < CallableDecl > {
188311 let source = fs:: read_to_string ( path)
189312 . unwrap_or_else ( |err| panic ! ( "failed to read {}: {err}" , path. display( ) ) ) ;
@@ -214,6 +337,7 @@ fn parse_source_file(path: &Path, spec: &SourceSpec, _order_offset: usize) -> Ve
214337 return_label : return_type_label ( & function. sig . output ) ,
215338 static_return_type : static_return_type_label ( & function. sig . output ) ,
216339 wrapper,
340+ host_binding_kind : classify_host_binding ( function) ,
217341 } ) ;
218342 }
219343 out
@@ -765,7 +889,7 @@ fn render_builtin_runtime_dispatch(
765889 . as_ref ( )
766890 . expect ( "host wrappers should exist" ) ;
767891 let adapter_name = host_wrapper_adapter_name ( callable) ;
768- if wrapper_uses_vm ( wrapper ) {
892+ if callable . host_binding_kind == HostBindingKind :: StaticStack {
769893 writeln ! (
770894 & mut out,
771895 "fn {adapter_name}(vm: &mut Vm, args: &[Value]) -> VmResult<CallOutcome> {{"
@@ -799,11 +923,7 @@ fn render_builtin_runtime_dispatch(
799923 )
800924 . unwrap ( ) ;
801925 for callable in host_callables {
802- let wrapper = callable
803- . wrapper
804- . as_ref ( )
805- . expect ( "host wrappers should exist" ) ;
806- if wrapper_uses_vm ( wrapper) {
926+ if callable. host_binding_kind == HostBindingKind :: StaticStack {
807927 writeln ! (
808928 & mut out,
809929 " registry.register_static_stack({:?}, {}, {});" ,
@@ -812,6 +932,15 @@ fn render_builtin_runtime_dispatch(
812932 host_wrapper_adapter_name( callable)
813933 )
814934 . unwrap ( ) ;
935+ } else if callable. host_binding_kind == HostBindingKind :: StaticNonYieldingArgs {
936+ writeln ! (
937+ & mut out,
938+ " registry.register_static_non_yielding_args({:?}, {}, {});" ,
939+ callable. name,
940+ callable. params. len( ) ,
941+ host_wrapper_adapter_name( callable)
942+ )
943+ . unwrap ( ) ;
815944 } else {
816945 writeln ! (
817946 & mut out,
@@ -833,28 +962,11 @@ fn render_builtin_runtime_dispatch(
833962 . unwrap ( ) ;
834963 writeln ! ( & mut out, " match name {{" ) . unwrap ( ) ;
835964 for callable in host_callables {
836- let wrapper = callable
837- . wrapper
838- . as_ref ( )
839- . expect ( "host wrappers should exist" ) ;
965+ let bind_call = callable
966+ . host_binding_kind
967+ . render_bind_static_call ( & callable. name , & host_wrapper_adapter_name ( callable) ) ;
840968 writeln ! ( & mut out, " {:?} => {{" , callable. name) . unwrap ( ) ;
841- if wrapper_uses_vm ( wrapper) {
842- writeln ! (
843- & mut out,
844- " vm.bind_static_stack_function({:?}, {});" ,
845- callable. name,
846- host_wrapper_adapter_name( callable)
847- )
848- . unwrap ( ) ;
849- } else {
850- writeln ! (
851- & mut out,
852- " vm.bind_static_args_function({:?}, {});" ,
853- callable. name,
854- host_wrapper_adapter_name( callable)
855- )
856- . unwrap ( ) ;
857- }
969+ writeln ! ( & mut out, " {bind_call}" ) . unwrap ( ) ;
858970 writeln ! ( & mut out, " true" ) . unwrap ( ) ;
859971 writeln ! ( & mut out, " }}" ) . unwrap ( ) ;
860972 }
@@ -1606,13 +1718,6 @@ fn host_wrapper_adapter_name(callable: &CallableDecl) -> String {
16061718 format ! ( "__pd_host_adapter_{}" , callable. rust_ident)
16071719}
16081720
1609- fn wrapper_uses_vm ( wrapper : & WrapperDecl ) -> bool {
1610- wrapper
1611- . params
1612- . iter ( )
1613- . any ( |param| matches ! ( param, WrapperParamKind :: Vm ) )
1614- }
1615-
16161721fn generated_wrapper_decl ( function : & ItemFn ) -> WrapperDecl {
16171722 let mut params = Vec :: new ( ) ;
16181723 for input in & function. sig . inputs {
0 commit comments