1use std::collections::HashMap;
4
5use proc_macro2::{Span, TokenStream};
6use quote::{format_ident, quote};
7use syn::{
8 Error, FnArg, Ident, ItemTrait, Meta, Pat, Path, Result, ReturnType, Token, TraitItem, Type,
9};
10
11use crate::common::{Param, ParamType};
12
13pub struct R2GTraitRepr {
14 name: Ident,
15 fns: Vec<R2GFnRepr>,
16}
17
18impl TryFrom<&ItemTrait> for R2GTraitRepr {
19 type Error = Error;
20
21 fn try_from(trat: &ItemTrait) -> Result<Self> {
22 let trait_name = trat.ident.clone();
23 let mut fns = Vec::new();
24
25 let mut mem_cnt = 0;
26 for item in trat.items.iter() {
27 let TraitItem::Fn(fn_item) = item else {
28 sbail!("only fn items are supported");
29 };
30 let fn_name = fn_item.sig.ident.clone();
31 let mut params = Vec::new();
32 for param in fn_item.sig.inputs.iter() {
33 let FnArg::Typed(param) = param else {
34 sbail!("only typed fn args are supported")
35 };
36 let Pat::Ident(param_name) = param.pat.as_ref() else {
38 sbail!("only ident fn args are supported");
39 };
40 let param_type = ParamType::try_from(param.ty.as_ref())?;
42 params.push(Param {
43 name: param_name.ident.clone(),
44 ty: param_type,
45 });
46 }
47 let mut is_async = fn_item.sig.asyncness.is_some();
48 let ret = match &fn_item.sig.output {
49 ReturnType::Default => None,
50 ReturnType::Type(_, t) => match t.as_ref() {
51 Type::Path(_) => {
52 let param_type = ParamType::try_from(t.as_ref())?;
53 Some(param_type)
54 }
55 Type::ImplTrait(i) => {
57 let t_str = i
58 .bounds
59 .iter()
60 .find_map(|b| match b {
61 syn::TypeParamBound::Trait(t) => {
62 let last_seg = t.path.segments.last().unwrap();
63 if last_seg.ident != "Future" {
64 return None;
65 }
66 let arg = match &last_seg.arguments {
68 syn::PathArguments::AngleBracketed(a)
69 if a.args.len() == 1 =>
70 {
71 a.args.first().unwrap()
72 }
73 _ => return None,
74 };
75 match arg {
76 syn::GenericArgument::AssocType(t)
77 if t.ident == "Output" =>
78 {
79 let ret = Some(ParamType::try_from(&t.ty).unwrap());
81 if is_async {
82 panic!("async cannot be used with impl Future");
83 }
84 is_async = true;
85 ret
86 }
87 _ => None,
88 }
89 }
90 _ => None,
91 })
92 .ok_or_else(|| serr!("only future types are supported"))?;
93 Some(t_str)
94 }
95 _ => sbail!("only path type or impl trait returns are supported"),
96 },
97 };
98 if is_async && ret.is_none() {
99 sbail!("async function must have a return value")
100 }
101
102 let mut drop_safe_ret_params = false;
104 let mut ret_send = false;
105
106 let mut is_safe = true;
107 let has_reference = params.iter().any(|param| param.ty.is_reference);
108
109 if is_async {
110 let drop_safe = fn_item
111 .attrs
112 .iter()
113 .any(|attr|
114 matches!(&attr.meta, Meta::Path(p) if p.get_ident() == Some(&format_ident!("drop_safe")))
115 );
116 drop_safe_ret_params = fn_item
117 .attrs
118 .iter()
119 .any(|attr|
120 matches!(&attr.meta, Meta::Path(p) if p.get_ident() == Some(&format_ident!("drop_safe_ret")))
121 );
122 ret_send = fn_item
123 .attrs
124 .iter()
125 .any(|attr|
126 matches!(&attr.meta, Meta::Path(p) if p.get_ident() == Some(&format_ident!("send")))
127 );
128
129 if !drop_safe && !drop_safe_ret_params {
130 is_safe = false;
131 }
132 if (drop_safe || drop_safe_ret_params) && has_reference {
133 sbail!("drop_safe function cannot have reference parameters")
134 }
135 }
136
137 let go_ptr = fn_item
138 .attrs
139 .iter()
140 .all(|attr|
141 matches!(&attr.meta, Meta::Path(p) if p.get_ident() != Some(&format_ident!("go_pass_struct")))
142 );
143
144 let using_mem = fn_item
145 .attrs
146 .iter()
147 .any(|attr|
148 matches!(&attr.meta, Meta::Path(p) if p.get_ident() == Some(&format_ident!("mem")) || p.get_ident() == Some(&format_ident!("shm")))
149 );
150 let cgo_cb = fn_item
151 .attrs
152 .iter()
153 .any(|attr|
154 matches!(&attr.meta, Meta::Path(p) if p.get_ident() == Some(&format_ident!("cgo_callback")) || p.get_ident() == Some(&format_ident!("cgo")))
155 );
156 if using_mem && !is_async {
157 if ret.is_some() {
158 sbail!("function based on shm must be async or without return value")
159 } else {
160 is_safe = false;
161 }
162 }
163 let mem_call_id = if using_mem {
164 let id = mem_cnt;
165 mem_cnt += 1;
166 Some(id)
167 } else {
168 None
169 };
170
171 fns.push(R2GFnRepr {
172 name: fn_name,
173 is_async,
174 params,
175 ret,
176 is_safe,
177 drop_safe_ret_params,
178 ret_send,
179 ret_static: !has_reference,
180 cgo_cb,
181 go_ptr,
182 mem_call_id,
183 });
184 }
185 Ok(R2GTraitRepr {
186 name: trait_name,
187 fns,
188 })
189 }
190}
191
192pub struct R2GFnRepr {
193 name: Ident,
194 is_async: bool,
195 params: Vec<Param>,
196 ret: Option<ParamType>,
197 is_safe: bool,
198 drop_safe_ret_params: bool,
199 ret_send: bool,
200 ret_static: bool,
201 go_ptr: bool,
202 cgo_cb: bool,
203 mem_call_id: Option<usize>,
204}
205
206impl R2GTraitRepr {
207 pub fn fns(&self) -> &[R2GFnRepr] {
208 &self.fns
209 }
210
211 pub fn generate_go_exports(&self, levels: &HashMap<Ident, u8>) -> String {
213 let name = self.name.to_string();
214 let mut out: String = self
215 .fns
216 .iter()
217 .map(|f| f.to_go_export(&name, levels))
218 .collect();
219 let shm_cnt = self.fns.iter().filter(|f| f.mem_call_id.is_some()).count();
220 if shm_cnt != 0 {
221 let mem_ffi_handles = (0..shm_cnt)
222 .map(|id| format!("ringHandle{name}{id}"))
223 .collect::<Vec<String>>();
224 out.push_str(&format!("//export RingsInit{name}\nfunc RingsInit{name}(crr, crw C.QueueMeta) {{\nringsInit(crr, crw, []func(unsafe.Pointer, *ants.MultiPool, func(interface{{}}, []byte, uint)){{{}}})\n}}\n", mem_ffi_handles.join(",")));
225 }
226 out
227 }
228
229 pub fn generate_go_interface(&self) -> String {
231 let name = self.name.to_string();
238 let fns = self.fns.iter().map(|f| f.to_go_interface_method());
239
240 let mut out = String::new();
241 out.push_str(&format!("var {name}Impl {name}\n"));
242 out.push_str(&format!("type {name} interface {{\n"));
243 for f in fns {
244 out.push_str(&f);
245 out.push('\n');
246 }
247 out.push_str("}\n");
248 out
249 }
250
251 pub fn generate_rs(
253 &self,
254 binding_path: Option<&Path>,
255 queue_size: Option<usize>,
256 ) -> Result<TokenStream> {
257 const DEFAULT_BINDING_MOD: &str = "binding";
258 let path_prefix = match binding_path {
259 Some(p) => quote! {#p::},
260 None => {
261 let binding_mod = format_ident!("{DEFAULT_BINDING_MOD}");
262 quote! {#binding_mod::}
263 }
264 };
265 let (mut fn_trait_impls, mut fn_callbacks) = (
266 Vec::with_capacity(self.fns.len()),
267 Vec::with_capacity(self.fns.len()),
268 );
269 for f in self.fns.iter() {
270 fn_trait_impls.push(f.to_rs_impl(&self.name, &path_prefix)?);
271 fn_callbacks.push(f.to_rs_callback(&path_prefix)?);
272 }
273
274 let trait_name = &self.name;
275 let impl_struct_name = format_ident!("{}Impl", trait_name);
276
277 let mem_init_ffi = format_ident!("RingsInit{}", trait_name);
278 let mut shm_init = None;
279 let mut shm_init_extc = None;
280 let mem_cnt = self.fns.iter().filter(|f| f.mem_call_id.is_some()).count();
281 let queue_size = queue_size.unwrap_or(4096);
282 if mem_cnt != 0 {
283 let mem_ffi_handles = (0..mem_cnt).map(|id| format_ident!("mem_ffi_handle{}", id));
284 shm_init = Some(quote! {
285 ::std::thread_local! {
286 static WS: (::rust2go_mem_ffi::WriteQueue<::rust2go_mem_ffi::Payload>, ::rust2go_mem_ffi::SharedSlab) = {
287 unsafe {::rust2go_mem_ffi::init_mem_ffi(#mem_init_ffi as *const (), #queue_size, [#(#impl_struct_name::#mem_ffi_handles),*])}
288 };
289 }
290 });
291 shm_init_extc = Some(quote! {
292 extern "C" {
293 fn #mem_init_ffi(rr: ::rust2go_mem_ffi::QueueMeta, rw: ::rust2go_mem_ffi::QueueMeta);
294 }
295 })
296 }
297
298 Ok(quote! {
299 #shm_init_extc
300 pub struct #impl_struct_name;
301 impl #trait_name for #impl_struct_name {
302 #(#fn_trait_impls)*
303 }
304 impl #impl_struct_name {
305 #shm_init
306 #(#fn_callbacks)*
307 }
308 })
309 }
310}
311
312impl R2GFnRepr {
313 pub const fn name(&self) -> &Ident {
314 &self.name
315 }
316
317 pub const fn is_async(&self) -> bool {
318 self.is_async
319 }
320
321 pub const fn drop_safe_ret_params(&self) -> bool {
322 self.drop_safe_ret_params
323 }
324
325 pub const fn is_safe(&self) -> bool {
326 self.is_safe
327 }
328
329 pub fn params(&self) -> &[Param] {
330 &self.params
331 }
332
333 pub fn ret(&self) -> Option<&ParamType> {
334 self.ret.as_ref()
335 }
336
337 pub const fn ret_send(&self) -> bool {
338 self.ret_send
339 }
340
341 pub const fn ret_static(&self) -> bool {
342 self.ret_static
343 }
344
345 pub const fn mem_call_id(&self) -> Option<usize> {
346 self.mem_call_id
347 }
348
349 pub const fn cgo_callback(&self) -> bool {
350 self.cgo_cb
351 }
352
353 fn to_go_export(&self, trait_name: &str, levels: &HashMap<Ident, u8>) -> String {
354 let ref_mark = BoolMark::new(self.go_ptr, "&");
355 if let Some(mem_call_id) = self.mem_call_id {
356 let fn_sig = format!("func ringHandle{trait_name}{mem_call_id}(ptr unsafe.Pointer, pool *ants.MultiPool, post_func func(interface{{}}, []byte, uint)) {{\n");
357 let Some(ret) = &self.ret else {
358 return format!("{fn_sig}post_func(nil, nil, 0)\n}}\n");
359 };
360
361 let mut fn_body = String::new();
362 let params_len = self.params().len();
363 for (idx, p) in self.params().iter().enumerate() {
364 fn_body.push_str(&format!(
365 "{name}:=*(*C.{ref_type})(ptr)\n",
366 name = p.name,
367 ref_type = p.ty.to_c(false)
368 ));
369 if idx + 1 != params_len {
370 fn_body.push_str(&format!(
371 "ptr=unsafe.Pointer(uintptr(ptr)+unsafe.Sizeof({name}))\n",
372 name = p.name
373 ));
374 }
375 fn_body.push_str(&format!(
376 "{name}_:={cvt}({name})\n",
377 name = p.name,
378 cvt = p.ty.c_to_go_field_converter(levels).0
379 ));
380 }
381 fn_body.push_str("pool.Submit(func() {\n");
382 fn_body.push_str(&format!(
383 "resp := {trait_name}Impl.{fn_name}({ref_mark}{params})\n",
384 fn_name = self.name,
385 params = self
386 .params
387 .iter()
388 .map(|p| format!("{}_", p.name))
389 .collect::<Vec<_>>()
390 .join(", ")
391 ));
392 fn_body.push_str(&format!(
393 "resp_ref_size := uint(unsafe.Sizeof(C.{}{{}}))\n",
394 ret.to_c(false)
395 ));
396 let (g2c_cnt, g2c_cvt) = (
397 ret.go_to_c_field_counter(levels).0,
398 ret.go_to_c_field_converter(levels).0,
399 );
400 fn_body.push_str(&format!("resp_ref, buffer := cvt_ref_cap({g2c_cnt}, {g2c_cvt}, resp_ref_size)(&resp)\noffset := uint(len(buffer))\nbuffer = append(buffer, unsafe.Slice((*byte)(unsafe.Pointer(&resp_ref)), resp_ref_size)...)\n"));
401 fn_body.push_str("post_func(resp, buffer, offset)\n})\n");
402 let fn_ending = "}\n";
403 return format!("{fn_sig}{fn_body}{fn_ending}");
404 }
405
406 let mut out = String::new();
407 let fn_name = format!("C{}_{}", trait_name, self.name);
408 out.push_str(&format!("//export {fn_name}\nfunc {fn_name}("));
409 self.params
410 .iter()
411 .for_each(|p| out.push_str(&format!("{} C.{}, ", p.name, p.ty.to_c(false))));
412
413 let mut new_names = Vec::new();
414 let mut new_cvt = String::new();
415 for p in self.params.iter() {
416 let new_name = format_ident!("_new_{}", p.name);
417 let cvt = p.ty.c_to_go_field_converter(levels).0;
418 new_cvt.push_str(&format!("{new_name} := {cvt}({})\n", p.name));
419 new_names.push(format!("{ref_mark}{}", new_name));
420 }
421 match (self.is_async, &self.ret) {
422 (true, None) => panic!("async function must have a return value"),
423 (false, None) => {
424 out.push_str(") {\n");
429 out.push_str(&new_cvt);
430 out.push_str(&format!(
431 " {trait_name}Impl.{fn_name}({params})\n",
432 fn_name = self.name,
433 params = new_names.join(", ")
434 ));
435 out.push_str("}\n");
436 }
437 (false, Some(ret)) => {
438 out.push_str("slot *C.void, cb *C.void) {\n");
448 out.push_str(&new_cvt);
449 out.push_str(&format!(
450 "resp := {trait_name}Impl.{fn_name}({params})\n",
451 fn_name = self.name,
452 params = new_names.join(", ")
453 ));
454 let (g2c_cnt, g2c_cvt) = (
455 ret.go_to_c_field_counter(levels).0,
456 ret.go_to_c_field_converter(levels).0,
457 );
458 out.push_str(&format!(
459 "resp_ref, buffer := cvt_ref({g2c_cnt}, {g2c_cvt})(&resp)\n"
460 ));
461 if self.cgo_cb {
462 out.push_str("cgocall.CallFuncG0P2(unsafe.Pointer(cb), unsafe.Pointer(&resp_ref), unsafe.Pointer(slot))\n");
463 } else {
464 out.push_str("asmcall.CallFuncG0P2(unsafe.Pointer(cb), unsafe.Pointer(&resp_ref), unsafe.Pointer(slot))\n");
465 }
466 out.push_str("runtime.KeepAlive(resp_ref)\nruntime.KeepAlive(resp)\nruntime.KeepAlive(buffer)\n");
467 out.push_str("}\n");
468 }
469 (true, Some(ret)) => {
470 out.push_str("slot *C.void, cb *C.void) {\n");
483 out.push_str(&new_cvt);
484 out.push_str(" go func() {\n");
485 out.push_str(&format!(
486 "resp := {trait_name}Impl.{fn_name}({params})\n",
487 fn_name = self.name,
488 params = new_names.join(", ")
489 ));
490 let (g2c_cnt, g2c_cvt) = (
491 ret.go_to_c_field_counter(levels).0,
492 ret.go_to_c_field_converter(levels).0,
493 );
494 out.push_str(&format!(
495 "resp_ref, buffer := cvt_ref({g2c_cnt}, {g2c_cvt})(&resp)\n"
496 ));
497 if self.cgo_cb {
498 out.push_str("cgocall.CallFuncG0P2(unsafe.Pointer(cb), unsafe.Pointer(&resp_ref), unsafe.Pointer(slot))\n");
499 } else {
500 out.push_str("asmcall.CallFuncG0P2(unsafe.Pointer(cb), unsafe.Pointer(&resp_ref), unsafe.Pointer(slot))\n");
501 }
502 out.push_str("runtime.KeepAlive(resp_ref)\nruntime.KeepAlive(resp)\nruntime.KeepAlive(buffer)\n");
503 out.push_str("}()\n}\n");
504 }
505 }
506 out
507 }
508
509 fn to_go_interface_method(&self) -> String {
510 let star_mark = BoolMark::new(self.go_ptr, "*");
513 format!(
514 "{}({}) {}",
515 self.name,
516 self.params
517 .iter()
518 .map(|p| format!("{} {star_mark}{}", p.name, p.ty.to_go()))
519 .collect::<Vec<_>>()
520 .join(", "),
521 self.ret.as_ref().map(|p| p.to_go()).unwrap_or_default()
522 )
523 }
524
525 fn to_rs_impl(&self, trait_name: &Ident, path_prefix: &TokenStream) -> Result<TokenStream> {
526 let mut out = TokenStream::default();
527
528 let func_name = &self.name;
529 let callback_name = format_ident!("{func_name}_cb");
530 let func_param_names: Vec<_> = self.params.iter().map(|p| &p.name).collect();
531 let func_param_types: Vec<_> = self.params.iter().map(|p| &p.ty).collect();
532 let unsafe_marker = (!self.is_safe).then(syn::token::Unsafe::default);
533 out.extend(quote! {
534 #unsafe_marker fn #func_name(#(#func_param_names: #func_param_types),*)
535 });
536
537 let ref_marks = self.params.iter().map(|p| {
538 if p.ty.is_reference {
539 None
540 } else {
541 Some(Token))
542 }
543 });
544 let c_func_name = format_ident!("C{trait_name}_{func_name}");
545 match (self.is_async, &self.ret) {
546 (true, None) => sbail!("async function must have a return value"),
547 (false, None) => {
548 if let Some(mem_call_id) = self.mem_call_id {
549 let mem_call_id = mem_call_id as u32;
567 out.extend(quote! {
568 {
569 const CALL_ID: u32 = #mem_call_id;
570 let (buf, ptr) = ::rust2go::ToRef::calc_ref(&::rust2go::CopyStruct((#(&#func_param_names,)*)));
571 Self::WS.with(|(wq, sb)| {
572 let sid = ::rust2go_mem_ffi::push_slab(sb, ::rust2go_mem_ffi::TaskDesc {
573 buf,
574 params_ptr: 0,
575 slot_ptr: 0,
576 });
577 wq.push(::rust2go_mem_ffi::Payload::new_call(
578 CALL_ID,
579 sid,
580 ptr as usize,
581 ));
582 });
583 }
584 });
585 } else {
586 out.extend(quote! {
591 {
592 #(
593 let (_buf, #func_param_names) = ::rust2go::ToRef::calc_ref(#ref_marks #func_param_names);
594 )*
595 #[allow(clippy::useless_transmute)]
596 unsafe {#path_prefix #c_func_name(#(::std::mem::transmute(#func_param_names)),*)}
597 }
598 });
599 }
600 }
601 (false, Some(ret)) => {
602 if self.mem_call_id.is_some() {
603 sbail!("sync function with return value cannot be shm call")
604 }
605 out.extend(quote!{
617 -> #ret {
618 let mut slot = None;
619 #(
620 let (_buf, #func_param_names) = ::rust2go::ToRef::calc_ref(#ref_marks #func_param_names);
621 )*
622 #[allow(clippy::useless_transmute)]
623 unsafe { #path_prefix #c_func_name(#(::std::mem::transmute(#func_param_names),)* &slot as *const _ as *const () as *mut _, Self::#callback_name as *const () as *mut _) };
624 slot.take().unwrap()
625 }
626 });
627 }
628 (true, Some(ret)) => {
629 if let Some(mem_call_id) = self.mem_call_id {
630 let mem_call_id = mem_call_id as u32;
651 let fut_output = if self.drop_safe_ret_params {
652 quote! { (#ret, (#(#func_param_types,)*)) }
653 } else {
654 quote! { #ret }
655 };
656 out.extend(quote! {
657 -> impl ::std::future::Future<Output = #fut_output> {
658 const CALL_ID: u32 = #mem_call_id;
659
660 let (buf, ptr) = ::rust2go::ToRef::calc_ref(&::rust2go::CopyStruct((#(&#func_param_names,)*)));
661 let slot = ::rust2go_mem_ffi::new_shared_mut(::rust2go_mem_ffi::SlotInner::<#fut_output>::new());
662 let slot_ptr = ::rust2go_mem_ffi::Shared::into_raw(slot.clone()) as usize;
663 Self::WS.with(|(wq, sb)| {
664 let sid = ::rust2go_mem_ffi::push_slab(sb, ::rust2go_mem_ffi::TaskDesc {
665 buf,
666 params_ptr: Box::into_raw(Box::new((#(#func_param_names,)*))) as usize,
667 slot_ptr,
668 });
669 let payload = ::rust2go_mem_ffi::Payload::new_call(CALL_ID, sid, ptr as usize);
670 wq.push(payload)
671 });
672 ::rust2go_mem_ffi::LocalFut { slot }
673 }
674 });
675 } else {
676 let len = self.params.len();
694 let tuple_ids = (0..len).map(syn::Index::from);
695 let new_fn = match self.drop_safe_ret_params {
696 false => quote! {::rust2go::ResponseFuture::new_without_req},
697 true => quote! {::rust2go::ResponseFuture::new},
698 };
699 let ret = match self.drop_safe_ret_params {
700 false => quote! { #ret },
701 true => quote! { (#ret, (#(#func_param_types,)*)) },
702 };
703 out.extend(quote! {
704 -> impl ::std::future::Future<Output = #ret> {
705 #new_fn(
706 |r_ref: <(#(#func_param_types,)*) as ::rust2go::ToRef>::Ref, slot: *const (), cb: *const ()| {
707 #[allow(clippy::useless_transmute)]
708 unsafe {
709 #path_prefix #c_func_name(
710 #(::std::mem::transmute(r_ref.#tuple_ids),)*
711 slot as *const _ as *mut _,
712 cb as *const _ as *mut _,
713 )
714 };
715 },
716 (#(#func_param_names,)*),
717 Self::#callback_name as *const (),
718 )
719 }
720 });
721 }
722 }
723 }
724 Ok(out)
725 }
726
727 fn to_rs_callback(&self, path_prefix: &TokenStream) -> Result<TokenStream> {
728 if let Some(mem_call_id) = self.mem_call_id {
729 let fn_name = format_ident!("mem_ffi_handle{}", mem_call_id);
730 let drop = if self.ret.is_some() {
731 quote! { true }
732 } else {
733 quote! { false }
734 };
735
736 let mut body = None;
737 if let Some(ret) = self.ret.as_ref() {
738 let resp_ref_ty = ret.to_rust_ref(None);
739 let reqs_ty = self.params().iter().map(|p| &p.ty);
740 let set_result = if self.drop_safe_ret_params {
741 quote! {
742 ::rust2go_mem_ffi::set_result_for_shared_mut_slot(&slot, (value, *_params));
743 }
744 } else {
745 quote! {
746 ::rust2go_mem_ffi::set_result_for_shared_mut_slot(&slot, value);
747 }
748 };
749 body = Some(quote! {
750 let value_ref = unsafe { &*(response_ptr as *const #resp_ref_ty) };
751 let value: #ret = ::rust2go::FromRef::from_ref(value_ref);
752
753 let _params = unsafe { Box::from_raw(desc.params_ptr as *mut (#(#reqs_ty,)*)) };
754
755 let slot = unsafe { ::rust2go_mem_ffi::shared_mut_from_raw(desc.slot_ptr) };
756 #set_result
757 });
758 }
759
760 return Ok(quote! {
761 #[allow(unused_variables)]
762 fn #fn_name(response_ptr: usize, desc: ::rust2go_mem_ffi::TaskDesc) -> bool {
763 #body
764 #drop
765 }
766 });
767 }
768
769 let fn_name = format_ident!("{}_cb", self.name);
770
771 match (self.is_async, &self.ret) {
772 (true, None) => sbail!("async function must have a return value"),
773 (false, None) => {
774 Ok(TokenStream::default())
776 }
777 (false, Some(ret)) => {
778 let resp_ref_ty = ret.to_rust_ref(Some(path_prefix));
783 Ok(quote! {
784 #[allow(clippy::useless_transmute, clippy::transmute_ptr_to_ref)]
785 #[no_mangle]
786 unsafe extern "C" fn #fn_name(resp: *const #resp_ref_ty, slot: *const ()) {
787 *(slot as *mut Option<#ret>) = Some(::rust2go::FromRef::from_ref(::std::mem::transmute(resp)));
788 }
789 })
790 }
791 (true, Some(ret)) => {
792 let resp_ref_ty = ret.to_rust_ref(Some(path_prefix));
800 let func_param_types = self.params.iter().map(|p| &p.ty);
801 Ok(quote! {
802 #[allow(clippy::useless_transmute, clippy::transmute_ptr_to_ref)]
803 #[no_mangle]
804 unsafe extern "C" fn #fn_name(resp: *const #resp_ref_ty, slot: *const ()) {
805 ::rust2go::SlotWriter::<#ret, ((#(#func_param_types,)*), Vec<u8>)>::from_ptr(slot).write(::rust2go::FromRef::from_ref(::std::mem::transmute(resp)));
806 }
807 })
808 }
809 }
810 }
811}
812
813struct BoolMark {
814 mark: bool,
815 fmt: &'static str,
816}
817impl BoolMark {
818 fn new(mark: bool, fmt: &'static str) -> Self {
819 Self { mark, fmt }
820 }
821}
822impl std::fmt::Display for BoolMark {
823 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
824 if self.mark {
825 return write!(f, "{}", self.fmt);
826 }
827 Ok(())
828 }
829}