1use crate::conversions::helpers::{core_prim_str, needs_f64_cast, needs_i32_cast};
2use crate::generators::{AsyncPattern, RustBindingConfig};
3use crate::type_mapper::TypeMapper;
4use ahash::AHashSet;
5use alef_core::ir::{CoreWrapper, ParamDef, TypeDef, TypeRef};
6
7fn arc_wrap(val: &str, name: &str, mutex_types: &AHashSet<String>) -> String {
12 let needs_mutex = mutex_types.contains(name);
13 crate::template_env::render(
14 "binding_helpers/arc_wrap.jinja",
15 minijinja::context! {
16 val => val,
17 needs_mutex => needs_mutex,
18 },
19 )
20 .trim_end_matches('\n')
21 .to_string()
22}
23
24fn expr_is_already_arc(expr: &str) -> bool {
31 let trimmed = expr.trim();
32 trimmed == "self.inner" || trimmed == "self.inner.clone()" || trimmed == "self.inner.as_ref().clone()"
33}
34
35#[allow(clippy::too_many_arguments)]
49pub fn wrap_return_with_mutex(
50 expr: &str,
51 return_type: &TypeRef,
52 type_name: &str,
53 opaque_types: &AHashSet<String>,
54 mutex_types: &AHashSet<String>,
55 self_is_opaque: bool,
56 returns_ref: bool,
57 returns_cow: bool,
58) -> String {
59 wrap_return_with_mutex_mapped(
60 expr,
61 return_type,
62 type_name,
63 opaque_types,
64 mutex_types,
65 self_is_opaque,
66 returns_ref,
67 returns_cow,
68 &crate::type_mapper::IdentityMapper,
69 )
70}
71
72#[allow(clippy::too_many_arguments)]
73pub fn wrap_return_with_mutex_mapped(
74 expr: &str,
75 return_type: &TypeRef,
76 type_name: &str,
77 opaque_types: &AHashSet<String>,
78 mutex_types: &AHashSet<String>,
79 self_is_opaque: bool,
80 returns_ref: bool,
81 returns_cow: bool,
82 mapper: &dyn TypeMapper,
83) -> String {
84 let self_arc = arc_wrap("", type_name, mutex_types); let _ = self_arc; match return_type {
87 TypeRef::Named(n) if n == type_name && self_is_opaque => {
88 if expr_is_already_arc(expr) {
91 return format!("Self {{ inner: {expr} }}");
92 }
93 let inner = if returns_cow {
94 format!("{expr}.into_owned()")
95 } else if returns_ref {
96 format!("{expr}.clone()")
97 } else {
98 expr.to_string()
99 };
100 format!("Self {{ inner: {} }}", arc_wrap(&inner, type_name, mutex_types))
101 }
102 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
103 let mapped_n = mapper.named(n);
104 if expr_is_already_arc(expr) {
106 return format!("{mapped_n} {{ inner: {expr} }}");
107 }
108 let inner = if returns_cow {
109 format!("{expr}.into_owned()")
110 } else if returns_ref {
111 format!("{expr}.clone()")
112 } else {
113 expr.to_string()
114 };
115 format!("{mapped_n} {{ inner: {} }}", arc_wrap(&inner, n, mutex_types))
116 }
117 TypeRef::Named(_) => {
118 if returns_cow {
125 format!("{expr}.into_owned().into()")
126 } else if returns_ref {
127 format!("{expr}.clone().into()")
128 } else {
129 format!("{expr}.into()")
130 }
131 }
132 TypeRef::String => {
134 if returns_ref {
135 format!("{expr}.into()")
136 } else {
137 expr.to_string()
138 }
139 }
140 TypeRef::Bytes => format!("{expr}.to_vec()"),
143 TypeRef::Path => format!("{expr}.to_string_lossy().to_string()"),
145 TypeRef::Duration => format!("{expr}.as_millis() as u64"),
147 TypeRef::Json => format!("{expr}.to_string()"),
149 TypeRef::Optional(inner) => match inner.as_ref() {
151 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
152 let mapped_n = mapper.named(n);
153 let wrap = arc_wrap("v", n, mutex_types);
154 if returns_ref {
155 format!(
156 "{expr}.map(|v| {mapped_n} {{ inner: {} }})",
157 arc_wrap("v.clone()", n, mutex_types)
158 )
159 } else {
160 format!("{expr}.map(|v| {mapped_n} {{ inner: {wrap} }})")
161 }
162 }
163 TypeRef::Named(_) => {
164 if returns_ref {
165 format!("{expr}.map(|v| v.clone().into())")
166 } else {
167 format!("{expr}.map(Into::into)")
168 }
169 }
170 TypeRef::Path => {
171 format!("{expr}.map(Into::into)")
172 }
173 TypeRef::String | TypeRef::Bytes => {
174 if returns_ref {
175 format!("{expr}.map(Into::into)")
176 } else {
177 expr.to_string()
178 }
179 }
180 TypeRef::Duration => format!("{expr}.map(|d| d.as_millis() as u64)"),
181 TypeRef::Json => format!("{expr}.map(ToString::to_string)"),
182 TypeRef::Vec(vec_inner) => match vec_inner.as_ref() {
184 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
185 let mapped_n = mapper.named(n);
186 if returns_ref {
187 let wrap = arc_wrap("x.clone()", n, mutex_types);
188 format!("{expr}.map(|v| v.into_iter().map(|x| {mapped_n} {{ inner: {wrap} }}).collect())")
189 } else {
190 let wrap = arc_wrap("x", n, mutex_types);
191 format!("{expr}.map(|v| v.into_iter().map(|x| {mapped_n} {{ inner: {wrap} }}).collect())")
192 }
193 }
194 TypeRef::Named(_) => {
195 if returns_ref {
196 format!("{expr}.map(|v| v.into_iter().map(|x| x.clone().into()).collect())")
197 } else {
198 format!("{expr}.map(|v| v.into_iter().map(Into::into).collect())")
199 }
200 }
201 _ => expr.to_string(),
202 },
203 _ => expr.to_string(),
204 },
205 TypeRef::Vec(inner) => match inner.as_ref() {
207 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
208 let mapped_n = mapper.named(n);
209 if returns_ref {
210 let wrap = arc_wrap("v.clone()", n, mutex_types);
211 format!("{expr}.into_iter().map(|v| {mapped_n} {{ inner: {wrap} }}).collect()")
212 } else {
213 let wrap = arc_wrap("v", n, mutex_types);
214 format!("{expr}.into_iter().map(|v| {mapped_n} {{ inner: {wrap} }}).collect()")
215 }
216 }
217 TypeRef::Named(_) => {
218 if returns_ref {
219 format!("{expr}.iter().map(|v| v.clone().into()).collect()")
222 } else {
223 format!("{expr}.into_iter().map(Into::into).collect()")
224 }
225 }
226 TypeRef::Path => {
227 format!("{expr}.into_iter().map(Into::into).collect()")
228 }
229 TypeRef::String => {
230 if returns_ref {
231 format!("{expr}.iter().map(|s| s.to_string()).collect()")
235 } else {
236 expr.to_string()
237 }
238 }
239 TypeRef::Bytes => {
240 if returns_ref {
241 format!("{expr}.iter().map(|b| b.to_vec()).collect()")
242 } else {
243 expr.to_string()
244 }
245 }
246 _ => expr.to_string(),
247 },
248 _ => expr.to_string(),
249 }
250}
251
252pub fn wrap_return(
257 expr: &str,
258 return_type: &TypeRef,
259 type_name: &str,
260 opaque_types: &AHashSet<String>,
261 self_is_opaque: bool,
262 returns_ref: bool,
263 returns_cow: bool,
264) -> String {
265 wrap_return_with_mutex(
266 expr,
267 return_type,
268 type_name,
269 opaque_types,
270 &AHashSet::new(),
271 self_is_opaque,
272 returns_ref,
273 returns_cow,
274 )
275}
276
277pub fn apply_return_newtype_unwrap(expr: &str, return_newtype_wrapper: &Option<String>) -> String {
282 match return_newtype_wrapper {
283 Some(_) => crate::template_env::render(
284 "binding_helpers/return_newtype_unwrap.jinja",
285 minijinja::context! {
286 expr => expr,
287 },
288 )
289 .trim_end_matches('\n')
290 .to_string(),
291 None => expr.to_string(),
292 }
293}
294
295pub fn gen_call_args(params: &[ParamDef], opaque_types: &AHashSet<String>) -> String {
306 params
307 .iter()
308 .enumerate()
309 .map(|(idx, p)| {
310 let promoted = crate::shared::is_promoted_optional(params, idx);
311 let unwrap_suffix = if promoted && p.optional {
316 format!(".expect(\"'{}' is required\")", p.name)
317 } else {
318 String::new()
319 };
320 if let Some(newtype_path) = &p.newtype_wrapper {
323 return if p.optional {
324 format!("{}.map({newtype_path})", p.name)
325 } else if promoted {
326 format!("{newtype_path}({}{})", p.name, unwrap_suffix)
327 } else {
328 format!("{newtype_path}({})", p.name)
329 };
330 }
331 match &p.ty {
332 TypeRef::Named(name) if opaque_types.contains(name.as_str()) => {
333 if p.optional {
335 format!("{}.as_ref().map(|v| &v.inner)", p.name)
336 } else if promoted {
337 format!("{}{}.inner.as_ref()", p.name, unwrap_suffix)
338 } else {
339 format!("&{}.inner", p.name)
340 }
341 }
342 TypeRef::Named(_) => {
343 if p.optional {
344 if p.is_ref {
345 format!("{}.as_ref()", p.name)
348 } else {
349 format!("{}.map(Into::into)", p.name)
350 }
351 } else if promoted {
352 format!("{}{}.into()", p.name, unwrap_suffix)
353 } else {
354 format!("{}.into()", p.name)
355 }
356 }
357 TypeRef::String | TypeRef::Char => {
361 if p.optional {
362 if p.is_ref {
363 format!("{}.as_deref()", p.name)
364 } else {
365 p.name.clone()
366 }
367 } else if promoted {
368 if p.is_ref {
369 format!("&{}{}", p.name, unwrap_suffix)
370 } else {
371 format!("{}{}", p.name, unwrap_suffix)
372 }
373 } else if p.is_ref {
374 format!("&{}", p.name)
375 } else {
376 p.name.clone()
377 }
378 }
379 TypeRef::Path => {
381 if p.optional && p.is_ref {
382 format!("{}.as_deref().map(std::path::Path::new)", p.name)
383 } else if p.optional {
384 format!("{}.map(std::path::PathBuf::from)", p.name)
385 } else if promoted {
386 format!("std::path::PathBuf::from({}{})", p.name, unwrap_suffix)
387 } else if p.is_ref {
388 format!("std::path::Path::new(&{})", p.name)
389 } else {
390 format!("std::path::PathBuf::from({})", p.name)
391 }
392 }
393 TypeRef::Bytes => {
394 if p.optional {
395 if p.is_ref {
396 format!("{}.as_deref()", p.name)
397 } else {
398 p.name.clone()
399 }
400 } else if promoted {
401 if p.is_ref {
404 format!("&{}{}", p.name, unwrap_suffix)
405 } else {
406 format!("{}{}", p.name, unwrap_suffix)
407 }
408 } else {
409 if p.is_ref {
412 format!("&{}", p.name)
413 } else {
414 p.name.clone()
415 }
416 }
417 }
418 TypeRef::Duration => {
420 if p.optional {
421 format!("{}.map(std::time::Duration::from_millis)", p.name)
422 } else if promoted {
423 format!("std::time::Duration::from_millis({}{})", p.name, unwrap_suffix)
424 } else {
425 format!("std::time::Duration::from_millis({})", p.name)
426 }
427 }
428 TypeRef::Json => {
429 if p.optional {
431 format!("{}.as_ref().and_then(|s| serde_json::from_str(s).ok())", p.name)
432 } else if promoted {
433 format!("serde_json::from_str(&{}{}).unwrap_or_default()", p.name, unwrap_suffix)
434 } else {
435 format!("serde_json::from_str(&{}).unwrap_or_default()", p.name)
436 }
437 }
438 TypeRef::Vec(inner) => {
439 if matches!(inner.as_ref(), TypeRef::Named(_)) {
441 if p.optional {
442 if p.is_ref {
443 format!("{}.as_deref()", p.name)
444 } else {
445 p.name.clone()
446 }
447 } else if promoted {
448 if p.is_ref {
449 format!("&{}{}", p.name, unwrap_suffix)
450 } else {
451 format!("{}{}", p.name, unwrap_suffix)
452 }
453 } else if p.is_ref {
454 format!("&{}", p.name)
455 } else {
456 p.name.clone()
457 }
458 } else if promoted {
459 format!("{}{}", p.name, unwrap_suffix)
460 } else if p.is_mut && p.optional {
461 format!("{}.as_deref_mut()", p.name)
462 } else if p.is_mut {
463 format!("&mut {}", p.name)
464 } else if p.is_ref && p.optional {
465 format!("{}.as_deref()", p.name)
466 } else if p.is_ref {
467 format!("&{}", p.name)
468 } else {
469 p.name.clone()
470 }
471 }
472 _ => {
473 if promoted {
474 format!("{}{}", p.name, unwrap_suffix)
475 } else if p.is_mut && p.optional {
476 format!("{}.as_deref_mut()", p.name)
477 } else if p.is_mut {
478 format!("&mut {}", p.name)
479 } else if p.is_ref && p.optional {
480 format!("{}.as_deref()", p.name)
483 } else if p.is_ref {
484 format!("&{}", p.name)
485 } else {
486 p.name.clone()
487 }
488 }
489 }
490 })
491 .collect::<Vec<_>>()
492 .join(", ")
493}
494
495pub fn gen_call_args_cfg(
502 params: &[ParamDef],
503 opaque_types: &AHashSet<String>,
504 cast_uints_to_i32: bool,
505 cast_large_ints_to_f64: bool,
506) -> String {
507 params
508 .iter()
509 .enumerate()
510 .map(|(idx, p)| {
511 let promoted = crate::shared::is_promoted_optional(params, idx);
512 let unwrap_suffix = if promoted && p.optional {
513 format!(".expect(\"'{}' is required\")", p.name)
514 } else {
515 String::new()
516 };
517 if p.newtype_wrapper.is_some() {
519 return gen_call_args(std::slice::from_ref(p), opaque_types);
522 }
523 if let TypeRef::Primitive(prim) = &p.ty {
525 let core_ty = core_prim_str(prim);
526 let needs_cast =
527 (cast_uints_to_i32 && needs_i32_cast(prim)) || (cast_large_ints_to_f64 && needs_f64_cast(prim));
528 if needs_cast {
529 return if p.optional {
530 format!("{}.map(|v| v as {core_ty})", p.name)
531 } else if promoted {
532 format!("({}{}) as {core_ty}", p.name, unwrap_suffix)
533 } else {
534 format!("{} as {core_ty}", p.name)
535 };
536 }
537 }
538 gen_call_args(std::slice::from_ref(p), opaque_types)
540 })
541 .collect::<Vec<_>>()
542 .join(", ")
543}
544
545pub fn gen_call_args_with_let_bindings(params: &[ParamDef], opaque_types: &AHashSet<String>) -> String {
548 params
549 .iter()
550 .enumerate()
551 .map(|(idx, p)| {
552 let promoted = crate::shared::is_promoted_optional(params, idx);
553 let unwrap_suffix = if promoted {
554 format!(".expect(\"'{}' is required\")", p.name)
555 } else {
556 String::new()
557 };
558 if let Some(newtype_path) = &p.newtype_wrapper {
560 return if p.optional {
561 format!("{}.map({newtype_path})", p.name)
562 } else if promoted {
563 format!("{newtype_path}({}{})", p.name, unwrap_suffix)
564 } else {
565 format!("{newtype_path}({})", p.name)
566 };
567 }
568 match &p.ty {
569 TypeRef::Named(name) if opaque_types.contains(name.as_str()) => {
570 if p.optional {
571 format!("{}.as_ref().map(|v| &v.inner)", p.name)
572 } else if promoted {
573 format!("{}{}.inner.as_ref()", p.name, unwrap_suffix)
574 } else {
575 format!("&{}.inner", p.name)
576 }
577 }
578 TypeRef::Named(_) => {
579 if p.optional && p.is_ref {
580 format!("{}_core", p.name)
582 } else if p.is_ref {
583 format!("&{}_core", p.name)
585 } else {
586 format!("{}_core", p.name)
587 }
588 }
589 TypeRef::String | TypeRef::Char => {
590 if p.optional {
591 if p.is_ref {
592 format!("{}.as_deref()", p.name)
593 } else {
594 p.name.clone()
595 }
596 } else if promoted {
597 if p.is_ref {
598 format!("&{}{}", p.name, unwrap_suffix)
599 } else {
600 format!("{}{}", p.name, unwrap_suffix)
601 }
602 } else if p.is_ref {
603 format!("&{}", p.name)
604 } else {
605 p.name.clone()
606 }
607 }
608 TypeRef::Path => {
609 if promoted {
610 format!("std::path::PathBuf::from({}{})", p.name, unwrap_suffix)
611 } else if p.optional && p.is_ref {
612 format!("{}.as_deref().map(std::path::Path::new)", p.name)
613 } else if p.optional {
614 format!("{}.map(std::path::PathBuf::from)", p.name)
615 } else if p.is_ref {
616 format!("std::path::Path::new(&{})", p.name)
617 } else {
618 format!("std::path::PathBuf::from({})", p.name)
619 }
620 }
621 TypeRef::Bytes => {
622 if p.optional {
623 if p.is_ref {
624 format!("{}.as_deref()", p.name)
625 } else {
626 p.name.clone()
627 }
628 } else if promoted {
629 if p.is_ref {
632 format!("&{}{}", p.name, unwrap_suffix)
633 } else {
634 format!("{}{}", p.name, unwrap_suffix)
635 }
636 } else {
637 if p.is_ref {
640 format!("&{}", p.name)
641 } else {
642 p.name.clone()
643 }
644 }
645 }
646 TypeRef::Duration => {
647 if p.optional {
648 format!("{}.map(std::time::Duration::from_millis)", p.name)
649 } else if promoted {
650 format!("std::time::Duration::from_millis({}{})", p.name, unwrap_suffix)
651 } else {
652 format!("std::time::Duration::from_millis({})", p.name)
653 }
654 }
655 TypeRef::Vec(inner) => {
656 if matches!(inner.as_ref(), TypeRef::String) && p.sanitized && p.original_type.is_some() {
659 if p.optional && p.is_ref {
660 format!("{}_core.as_deref()", p.name)
661 } else if p.optional {
662 format!("{}_core", p.name)
663 } else if p.is_ref {
664 format!("&{}_core", p.name)
665 } else {
666 format!("{}_core", p.name)
667 }
668 } else if matches!(inner.as_ref(), TypeRef::Named(_)) {
669 if p.optional && p.is_ref {
671 format!("{}_core.as_deref()", p.name)
673 } else if p.optional {
674 format!("{}_core", p.name)
676 } else if p.is_ref {
677 format!("&{}_core", p.name)
678 } else {
679 format!("{}_core", p.name)
680 }
681 } else if matches!(inner.as_ref(), TypeRef::String | TypeRef::Char) && p.is_ref {
682 if p.optional {
685 format!("{}.as_deref()", p.name)
686 } else {
687 format!("&{}_refs", p.name)
688 }
689 } else if promoted {
690 format!("{}{}", p.name, unwrap_suffix)
691 } else if p.is_ref && p.optional {
692 format!("{}.as_deref()", p.name)
693 } else if p.is_ref {
694 format!("&{}", p.name)
695 } else {
696 p.name.clone()
697 }
698 }
699 _ => {
700 if promoted {
701 format!("{}{}", p.name, unwrap_suffix)
702 } else if p.is_ref && p.optional {
703 format!("{}.as_deref()", p.name)
704 } else if p.is_ref {
705 format!("&{}", p.name)
706 } else {
707 p.name.clone()
708 }
709 }
710 }
711 })
712 .collect::<Vec<_>>()
713 .join(", ")
714}
715
716pub fn gen_named_let_bindings_pub(params: &[ParamDef], opaque_types: &AHashSet<String>, core_import: &str) -> String {
718 gen_named_let_bindings(params, opaque_types, core_import)
719}
720
721pub fn gen_named_let_bindings_no_promote(
724 params: &[ParamDef],
725 opaque_types: &AHashSet<String>,
726 core_import: &str,
727) -> String {
728 gen_named_let_bindings_inner(params, opaque_types, core_import, false)
729}
730
731pub(super) fn gen_named_let_bindings(
732 params: &[ParamDef],
733 opaque_types: &AHashSet<String>,
734 core_import: &str,
735) -> String {
736 gen_named_let_bindings_inner(params, opaque_types, core_import, true)
737}
738
739pub(super) fn gen_named_let_bindings_by_ref(
743 params: &[ParamDef],
744 opaque_types: &AHashSet<String>,
745 core_import: &str,
746) -> String {
747 let mut bindings = String::new();
748 for (idx, p) in params.iter().enumerate() {
749 match &p.ty {
750 TypeRef::Named(name) if !opaque_types.contains(name.as_str()) => {
751 let promoted = crate::shared::is_promoted_optional(params, idx);
752 let core_type_path = format!("{core_import}::{name}");
753 let binding = if p.optional {
754 crate::template_env::render(
755 "binding_helpers/named_let_binding_by_ref_optional.jinja",
756 minijinja::context! {
757 name => &p.name,
758 core_type_path => &core_type_path,
759 },
760 )
761 } else if promoted {
762 crate::template_env::render(
763 "binding_helpers/named_let_binding_by_ref_promoted.jinja",
764 minijinja::context! {
765 name => &p.name,
766 core_type_path => &core_type_path,
767 },
768 )
769 } else {
770 crate::template_env::render(
771 "binding_helpers/named_let_binding_by_ref_simple.jinja",
772 minijinja::context! {
773 name => &p.name,
774 core_type_path => &core_type_path,
775 },
776 )
777 };
778 bindings.push_str(&binding);
779 bindings.push_str("\n ");
780 }
781 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if !opaque_types.contains(n.as_str())) => {
782 let binding = if p.optional {
783 crate::template_env::render(
784 "binding_helpers/vec_named_let_binding_by_ref_optional.jinja",
785 minijinja::context! {
786 name => &p.name,
787 },
788 )
789 } else {
790 let promoted = crate::shared::is_promoted_optional(params, idx);
791 if promoted {
792 crate::template_env::render(
793 "binding_helpers/vec_named_let_binding_by_ref_promoted.jinja",
794 minijinja::context! {
795 name => &p.name,
796 },
797 )
798 } else {
799 crate::template_env::render(
800 "binding_helpers/vec_named_let_binding_by_ref_simple.jinja",
801 minijinja::context! {
802 name => &p.name,
803 },
804 )
805 }
806 };
807 bindings.push_str(&binding);
808 bindings.push_str("\n ");
809 }
810 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::String | TypeRef::Char) && p.is_ref => {
811 let binding = if p.optional {
812 crate::template_env::render(
813 "binding_helpers/vec_string_refs_binding_optional.jinja",
814 minijinja::context! {
815 name => &p.name,
816 },
817 )
818 } else {
819 crate::template_env::render(
820 "binding_helpers/vec_string_refs_binding_simple.jinja",
821 minijinja::context! {
822 name => &p.name,
823 },
824 )
825 };
826 bindings.push_str(&binding);
827 bindings.push_str("\n ");
828 }
829 _ => {}
830 }
831 }
832 bindings
833}
834
835fn gen_named_let_bindings_inner(
836 params: &[ParamDef],
837 opaque_types: &AHashSet<String>,
838 core_import: &str,
839 promote: bool,
840) -> String {
841 let mut bindings = String::new();
842 for (idx, p) in params.iter().enumerate() {
843 match &p.ty {
844 TypeRef::Named(name) if !opaque_types.contains(name.as_str()) => {
845 let promoted = promote && crate::shared::is_promoted_optional(params, idx);
846 let core_type_path = format!("{}::{}", core_import, name);
847 let binding = if p.optional {
848 if p.is_ref {
849 crate::template_env::render(
850 "binding_helpers/named_let_binding_optional_ref.jinja",
851 minijinja::context! {
852 name => &p.name,
853 core_type_path => &core_type_path,
854 },
855 )
856 } else {
857 crate::template_env::render(
858 "binding_helpers/named_let_binding_optional.jinja",
859 minijinja::context! {
860 name => &p.name,
861 core_type_path => &core_type_path,
862 },
863 )
864 }
865 } else if promoted {
866 crate::template_env::render(
867 "binding_helpers/named_let_binding_promoted.jinja",
868 minijinja::context! {
869 name => &p.name,
870 core_type_path => &core_type_path,
871 },
872 )
873 } else {
874 crate::template_env::render(
875 "binding_helpers/named_let_binding_simple.jinja",
876 minijinja::context! {
877 name => &p.name,
878 core_type_path => &core_type_path,
879 },
880 )
881 };
882 bindings.push_str(&binding);
883 bindings.push_str("\n ");
884 }
885 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if !opaque_types.contains(n.as_str())) => {
886 let promoted = promote && crate::shared::is_promoted_optional(params, idx);
887 let binding = if p.optional && p.is_ref {
888 crate::template_env::render(
889 "binding_helpers/vec_named_let_binding_optional.jinja",
890 minijinja::context! {
891 name => &p.name,
892 },
893 )
894 } else if p.optional {
895 crate::template_env::render(
896 "binding_helpers/vec_named_let_binding_optional_no_ref.jinja",
897 minijinja::context! {
898 name => &p.name,
899 },
900 )
901 } else if promoted {
902 crate::template_env::render(
903 "binding_helpers/vec_named_let_binding_promoted.jinja",
904 minijinja::context! {
905 name => &p.name,
906 },
907 )
908 } else {
909 crate::template_env::render(
910 "binding_helpers/vec_named_let_binding_simple.jinja",
911 minijinja::context! {
912 name => &p.name,
913 },
914 )
915 };
916 bindings.push_str(&binding);
917 bindings.push_str("\n ");
918 }
919 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::String | TypeRef::Char) && p.is_ref => {
922 let binding = if p.optional {
923 crate::template_env::render(
924 "binding_helpers/vec_string_refs_binding_optional.jinja",
925 minijinja::context! {
926 name => &p.name,
927 },
928 )
929 } else {
930 crate::template_env::render(
931 "binding_helpers/vec_string_refs_binding_simple.jinja",
932 minijinja::context! {
933 name => &p.name,
934 },
935 )
936 };
937 bindings.push_str(&binding);
938 bindings.push_str("\n ");
939 }
940 TypeRef::Vec(inner)
942 if matches!(inner.as_ref(), TypeRef::String) && p.sanitized && p.original_type.is_some() =>
943 {
944 let template = if p.optional {
945 "binding_helpers/sanitized_vec_string_filter_optional.jinja"
946 } else {
947 "binding_helpers/sanitized_vec_string_filter_simple.jinja"
948 };
949 bindings.push_str(&crate::template_env::render(
950 template,
951 minijinja::context! {
952 name => &p.name,
953 },
954 ));
955 }
956 _ => {}
957 }
958 }
959 bindings
960}
961
962pub fn gen_serde_let_bindings(
969 params: &[ParamDef],
970 opaque_types: &AHashSet<String>,
971 core_import: &str,
972 err_conv: &str,
973 indent: &str,
974) -> String {
975 let mut bindings = String::new();
976 for (idx, p) in params.iter().enumerate() {
977 let promoted = crate::shared::is_promoted_optional(params, idx);
978 match &p.ty {
979 TypeRef::Named(name) if !opaque_types.contains(name.as_str()) => {
980 let core_path = format!("{}::{}", core_import, name);
981 if p.optional {
982 bindings.push_str(&crate::template_env::render(
983 "binding_helpers/serde_named_let_binding_optional.jinja",
984 minijinja::context! {
985 name => &p.name,
986 core_path => core_path,
987 err_conv => err_conv,
988 indent => indent,
989 },
990 ));
991 } else if promoted {
992 bindings.push_str(&crate::template_env::render(
996 "binding_helpers/serde_named_let_binding_promoted.jinja",
997 minijinja::context! {
998 name => &p.name,
999 core_path => core_path,
1000 err_conv => err_conv,
1001 indent => indent,
1002 },
1003 ));
1004 } else {
1005 bindings.push_str(&crate::template_env::render(
1006 "binding_helpers/serde_named_let_binding_simple.jinja",
1007 minijinja::context! {
1008 name => &p.name,
1009 core_path => core_path,
1010 err_conv => err_conv,
1011 indent => indent,
1012 },
1013 ));
1014 }
1015 }
1016 TypeRef::Vec(inner) => {
1017 if let TypeRef::Named(name) = inner.as_ref() {
1018 if !opaque_types.contains(name.as_str()) {
1019 let core_path = format!("{}::{}", core_import, name);
1020 if p.optional {
1021 bindings.push_str(&crate::template_env::render(
1022 "binding_helpers/serde_vec_named_optional.jinja",
1023 minijinja::context! {
1024 name => &p.name,
1025 core_path => core_path,
1026 err_conv => err_conv,
1027 indent => indent,
1028 },
1029 ));
1030 } else {
1031 bindings.push_str(&crate::template_env::render(
1032 "binding_helpers/serde_vec_named_simple.jinja",
1033 minijinja::context! {
1034 name => &p.name,
1035 core_path => core_path,
1036 err_conv => err_conv,
1037 indent => indent,
1038 },
1039 ));
1040 }
1041 }
1042 } else if matches!(inner.as_ref(), TypeRef::String) && p.sanitized && p.original_type.is_some() {
1043 let template = if p.optional {
1046 "binding_helpers/serde_sanitized_vec_string_optional.jinja"
1047 } else {
1048 "binding_helpers/serde_sanitized_vec_string_simple.jinja"
1049 };
1050 bindings.push_str(&crate::template_env::render(
1051 template,
1052 minijinja::context! {
1053 name => &p.name,
1054 err_conv => err_conv,
1055 indent => indent,
1056 },
1057 ));
1058 }
1059 }
1060 _ => {}
1061 }
1062 }
1063 bindings
1064}
1065
1066pub fn has_named_params(params: &[ParamDef], opaque_types: &AHashSet<String>) -> bool {
1071 params.iter().any(|p| match &p.ty {
1072 TypeRef::Named(name) if !opaque_types.contains(name.as_str()) => true,
1073 TypeRef::Vec(inner) => {
1074 matches!(inner.as_ref(), TypeRef::Named(name) if !opaque_types.contains(name.as_str()))
1078 || (matches!(inner.as_ref(), TypeRef::String | TypeRef::Char) && p.is_ref)
1079 || (matches!(inner.as_ref(), TypeRef::String) && p.sanitized && p.original_type.is_some())
1080 }
1081 _ => false,
1082 })
1083}
1084
1085pub fn is_simple_non_opaque_param(ty: &TypeRef) -> bool {
1093 match ty {
1094 TypeRef::Primitive(_)
1095 | TypeRef::String
1096 | TypeRef::Char
1097 | TypeRef::Bytes
1098 | TypeRef::Path
1099 | TypeRef::Unit
1100 | TypeRef::Duration
1101 | TypeRef::Json => true,
1102 TypeRef::Optional(inner) => is_simple_non_opaque_param(inner),
1103 _ => false,
1104 }
1105}
1106
1107pub fn gen_lossy_binding_to_core_fields(
1120 typ: &TypeDef,
1121 core_import: &str,
1122 option_duration_on_defaults: bool,
1123 opaque_types: &AHashSet<String>,
1124 cast_uints_to_i32: bool,
1125 cast_large_ints_to_f64: bool,
1126 skip_types: &[String],
1127) -> String {
1128 gen_lossy_binding_to_core_fields_inner(
1129 typ,
1130 core_import,
1131 false,
1132 option_duration_on_defaults,
1133 opaque_types,
1134 cast_uints_to_i32,
1135 cast_large_ints_to_f64,
1136 skip_types,
1137 )
1138}
1139
1140pub fn gen_lossy_binding_to_core_fields_mut(
1142 typ: &TypeDef,
1143 core_import: &str,
1144 option_duration_on_defaults: bool,
1145 opaque_types: &AHashSet<String>,
1146 cast_uints_to_i32: bool,
1147 cast_large_ints_to_f64: bool,
1148 skip_types: &[String],
1149) -> String {
1150 gen_lossy_binding_to_core_fields_inner(
1151 typ,
1152 core_import,
1153 true,
1154 option_duration_on_defaults,
1155 opaque_types,
1156 cast_uints_to_i32,
1157 cast_large_ints_to_f64,
1158 skip_types,
1159 )
1160}
1161
1162#[allow(clippy::too_many_arguments)]
1163fn gen_lossy_binding_to_core_fields_inner(
1164 typ: &TypeDef,
1165 core_import: &str,
1166 needs_mut: bool,
1167 option_duration_on_defaults: bool,
1168 opaque_types: &AHashSet<String>,
1169 cast_uints_to_i32: bool,
1170 cast_large_ints_to_f64: bool,
1171 skip_types: &[String],
1172) -> String {
1173 let core_path = crate::conversions::core_type_path(typ, core_import);
1174 let mut_kw = if needs_mut { "mut " } else { "" };
1175 let allow = if typ.has_stripped_cfg_fields {
1180 "#[allow(clippy::needless_update)]\n "
1181 } else {
1182 ""
1183 };
1184 let mut out = format!("{allow}let {mut_kw}core_self = {core_path} {{\n");
1185 for field in &typ.fields {
1186 if field.binding_excluded {
1187 out.push_str(&crate::template_env::render(
1188 "binding_helpers/struct_field_default.jinja",
1189 minijinja::context! {
1190 name => &field.name,
1191 },
1192 ));
1193 continue;
1194 }
1195 if field.cfg.is_some() {
1198 continue;
1199 }
1200 let name = &field.name;
1201 if field.sanitized && field.core_wrapper != CoreWrapper::Cow {
1202 out.push_str(&crate::template_env::render(
1203 "binding_helpers/struct_field_default.jinja",
1204 minijinja::context! {
1205 name => &field.name,
1206 },
1207 ));
1208 out.push('\n');
1209 continue;
1210 }
1211 let is_opaque_named = match &field.ty {
1216 TypeRef::Named(n) => opaque_types.contains(n.as_str()),
1217 TypeRef::Optional(inner) => {
1218 matches!(inner.as_ref(), TypeRef::Named(n) if opaque_types.contains(n.as_str()))
1219 }
1220 _ => false,
1221 };
1222 if is_opaque_named {
1223 out.push_str(&crate::template_env::render(
1224 "binding_helpers/struct_field_default.jinja",
1225 minijinja::context! {
1226 name => &field.name,
1227 },
1228 ));
1229 out.push('\n');
1230 continue;
1231 }
1232 let is_skip_named = match &field.ty {
1235 TypeRef::Named(n) => skip_types.contains(n),
1236 TypeRef::Optional(inner) => {
1237 matches!(inner.as_ref(), TypeRef::Named(n) if skip_types.contains(n))
1238 }
1239 _ => false,
1240 };
1241 if is_skip_named {
1242 out.push_str(&crate::template_env::render(
1243 "binding_helpers/default_field.jinja",
1244 minijinja::context! {
1245 name => &name,
1246 },
1247 ));
1248 continue;
1249 }
1250 let expr = match &field.ty {
1251 TypeRef::Primitive(p) if cast_uints_to_i32 && needs_i32_cast(p) => {
1252 let core_ty = core_prim_str(p);
1253 if field.optional {
1254 format!("self.{name}.map(|v| v as {core_ty})")
1255 } else {
1256 format!("self.{name} as {core_ty}")
1257 }
1258 }
1259 TypeRef::Primitive(p) if cast_large_ints_to_f64 && needs_f64_cast(p) => {
1260 let core_ty = core_prim_str(p);
1261 if field.optional {
1262 format!("self.{name}.map(|v| v as {core_ty})")
1263 } else {
1264 format!("self.{name} as {core_ty}")
1265 }
1266 }
1267 TypeRef::Primitive(_) => format!("self.{name}"),
1268 TypeRef::Duration => {
1269 if field.optional {
1270 format!("self.{name}.map(std::time::Duration::from_millis)")
1271 } else if option_duration_on_defaults && typ.has_default {
1272 format!("self.{name}.map(std::time::Duration::from_millis).unwrap_or_default()")
1277 } else {
1278 format!("std::time::Duration::from_millis(self.{name})")
1279 }
1280 }
1281 TypeRef::String => {
1282 if field.core_wrapper == CoreWrapper::Cow {
1283 format!("self.{name}.clone().into()")
1284 } else {
1285 format!("self.{name}.clone()")
1286 }
1287 }
1288 TypeRef::Bytes => {
1292 if field.core_wrapper == CoreWrapper::Bytes {
1293 format!("self.{name}.clone().into()")
1294 } else {
1295 format!("self.{name}.clone()")
1296 }
1297 }
1298 TypeRef::Char => {
1299 if field.optional {
1300 format!("self.{name}.as_ref().and_then(|s| s.chars().next())")
1301 } else {
1302 format!("self.{name}.chars().next().unwrap_or('*')")
1303 }
1304 }
1305 TypeRef::Path => {
1306 if field.optional {
1307 format!("self.{name}.clone().map(Into::into)")
1308 } else {
1309 format!("self.{name}.clone().into()")
1310 }
1311 }
1312 TypeRef::Named(_) => {
1313 if field.optional {
1314 format!("self.{name}.clone().map(Into::into)")
1315 } else {
1316 format!("self.{name}.clone().into()")
1317 }
1318 }
1319 TypeRef::Vec(inner) => match inner.as_ref() {
1320 TypeRef::Named(_) => {
1321 if field.optional {
1322 format!("self.{name}.clone().map(|v| v.into_iter().map(Into::into).collect())")
1324 } else {
1325 format!("self.{name}.clone().into_iter().map(Into::into).collect()")
1326 }
1327 }
1328 TypeRef::Primitive(p) if cast_uints_to_i32 && needs_i32_cast(p) => {
1330 let core_ty = core_prim_str(p);
1331 if field.optional {
1332 format!("self.{name}.clone().map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
1333 } else {
1334 format!("self.{name}.clone().into_iter().map(|v| v as {core_ty}).collect()")
1335 }
1336 }
1337 TypeRef::Primitive(p) if cast_large_ints_to_f64 && needs_f64_cast(p) => {
1339 let core_ty = core_prim_str(p);
1340 if field.optional {
1341 format!("self.{name}.clone().map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
1342 } else {
1343 format!("self.{name}.clone().into_iter().map(|v| v as {core_ty}).collect()")
1344 }
1345 }
1346 _ => format!("self.{name}.clone()"),
1347 },
1348 TypeRef::Optional(inner) => {
1349 let base = match inner.as_ref() {
1353 TypeRef::Named(_) => {
1354 format!("self.{name}.clone().map(Into::into)")
1355 }
1356 TypeRef::Duration => {
1357 format!("self.{name}.map(|v| std::time::Duration::from_millis(v as u64))")
1358 }
1359 TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_)) => {
1360 format!("self.{name}.clone().map(|v| v.into_iter().map(Into::into).collect())")
1361 }
1362 TypeRef::Vec(vi) => match vi.as_ref() {
1364 TypeRef::Primitive(p) if cast_uints_to_i32 && needs_i32_cast(p) => {
1365 let core_ty = core_prim_str(p);
1366 format!("self.{name}.clone().map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
1367 }
1368 TypeRef::Primitive(p) if cast_large_ints_to_f64 && needs_f64_cast(p) => {
1370 let core_ty = core_prim_str(p);
1371 format!("self.{name}.clone().map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
1372 }
1373 _ => format!("self.{name}.clone()"),
1374 },
1375 _ => format!("self.{name}.clone()"),
1376 };
1377 if field.optional {
1378 format!("({base}).map(Some)")
1379 } else {
1380 base
1381 }
1382 }
1383 TypeRef::Map(_, v) => match v.as_ref() {
1384 TypeRef::Json => {
1385 if field.optional {
1390 format!(
1391 "self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| \
1392 (k.into(), serde_json::from_str(&v).unwrap_or(serde_json::Value::String(v)))).collect())"
1393 )
1394 } else {
1395 format!(
1396 "self.{name}.clone().into_iter().map(|(k, v)| \
1397 (k.into(), serde_json::from_str(&v).unwrap_or(serde_json::Value::String(v)))).collect()"
1398 )
1399 }
1400 }
1401 TypeRef::Named(_) => {
1404 if field.optional {
1405 format!(
1406 "self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())"
1407 )
1408 } else {
1409 format!("self.{name}.clone().into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
1410 }
1411 }
1412 TypeRef::Primitive(p) if cast_uints_to_i32 && needs_i32_cast(p) => {
1414 let core_ty = core_prim_str(p);
1415 if field.optional {
1416 format!(
1417 "self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| (k.into(), v as {core_ty})).collect())"
1418 )
1419 } else {
1420 format!("self.{name}.clone().into_iter().map(|(k, v)| (k.into(), v as {core_ty})).collect()")
1421 }
1422 }
1423 TypeRef::Primitive(p) if cast_large_ints_to_f64 && needs_f64_cast(p) => {
1425 let core_ty = core_prim_str(p);
1426 if field.optional {
1427 format!(
1428 "self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| (k.into(), v as {core_ty})).collect())"
1429 )
1430 } else {
1431 format!("self.{name}.clone().into_iter().map(|(k, v)| (k.into(), v as {core_ty})).collect()")
1432 }
1433 }
1434 _ => {
1436 if field.optional {
1437 format!("self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
1438 } else {
1439 format!("self.{name}.clone().into_iter().map(|(k, v)| (k.into(), v)).collect()")
1440 }
1441 }
1442 },
1443 TypeRef::Unit => format!("self.{name}.clone()"),
1444 TypeRef::Json => {
1445 if field.optional {
1447 format!("self.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())")
1448 } else {
1449 format!("serde_json::from_str(&self.{name}).unwrap_or_default()")
1450 }
1451 }
1452 };
1453 let expr = if let Some(newtype_path) = &field.newtype_wrapper {
1458 match &field.ty {
1459 TypeRef::Optional(_) => format!("({expr}).map({newtype_path})"),
1460 TypeRef::Vec(_) => format!("({expr}).into_iter().map({newtype_path}).collect::<Vec<_>>()"),
1461 _ if field.optional => format!("({expr}).map({newtype_path})"),
1462 _ => format!("{newtype_path}({expr})"),
1463 }
1464 } else {
1465 expr
1466 };
1467 out.push_str(&crate::template_env::render(
1468 "binding_helpers/struct_field_line.jinja",
1469 minijinja::context! {
1470 name => &field.name,
1471 expr => &expr,
1472 },
1473 ));
1474 out.push('\n');
1475 }
1476 if typ.has_stripped_cfg_fields {
1478 out.push_str(" ..Default::default()\n");
1479 }
1480 out.push_str(" };\n ");
1481 out
1482}
1483
1484#[allow(clippy::too_many_arguments)]
1499pub fn gen_async_body(
1500 core_call: &str,
1501 cfg: &RustBindingConfig,
1502 has_error: bool,
1503 return_wrap: &str,
1504 is_opaque: bool,
1505 inner_clone_line: &str,
1506 is_unit_return: bool,
1507 return_type: Option<&str>,
1508) -> String {
1509 let pattern_body = match cfg.async_pattern {
1510 AsyncPattern::Pyo3FutureIntoPy => {
1511 let result_handling = if has_error {
1512 format!(
1513 "let result = {core_call}.await\n \
1514 .map_err(|e| PyErr::new::<PyRuntimeError, _>(e.to_string()))?;"
1515 )
1516 } else if is_unit_return {
1517 format!("{core_call}.await;")
1518 } else {
1519 format!("let result = {core_call}.await;")
1520 };
1521 let (ok_expr, extra_binding) = if is_unit_return && !has_error {
1522 ("()".to_string(), String::new())
1523 } else if return_wrap.contains(".into()") || return_wrap.contains("::from(") {
1524 let wrapped_var = "wrapped_result";
1528 let binding = if let Some(ret_type) = return_type {
1529 format!("let {wrapped_var}: {ret_type} = {return_wrap};\n ")
1531 } else {
1532 format!("let {wrapped_var} = {return_wrap};\n ")
1533 };
1534 (wrapped_var.to_string(), binding)
1535 } else {
1536 (return_wrap.to_string(), String::new())
1537 };
1538 crate::template_env::render(
1539 "binding_helpers/async_body_pyo3.jinja",
1540 minijinja::context! {
1541 result_handling => result_handling,
1542 extra_binding => extra_binding,
1543 ok_expr => ok_expr,
1544 },
1545 )
1546 }
1547 AsyncPattern::WasmNativeAsync => {
1548 let result_handling = if has_error {
1549 format!(
1550 "let result = {core_call}.await\n \
1551 .map_err(|e| JsValue::from_str(&e.to_string()))?;"
1552 )
1553 } else if is_unit_return {
1554 format!("{core_call}.await;")
1555 } else {
1556 format!("let result = {core_call}.await;")
1557 };
1558 let ok_expr = if is_unit_return && !has_error {
1559 "()"
1560 } else {
1561 return_wrap
1562 };
1563 crate::template_env::render(
1564 "binding_helpers/async_body_wasm.jinja",
1565 minijinja::context! {
1566 result_handling => result_handling,
1567 ok_expr => ok_expr,
1568 },
1569 )
1570 }
1571 AsyncPattern::NapiNativeAsync => {
1572 let result_handling = if has_error {
1573 format!(
1574 "let result = {core_call}.await\n \
1575 .map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))?;"
1576 )
1577 } else if is_unit_return {
1578 format!("{core_call}.await;")
1579 } else {
1580 format!("let result = {core_call}.await;")
1581 };
1582 let (needs_ok_wrapper, ok_expr) = if !has_error && !is_unit_return {
1583 (false, return_wrap.to_string())
1585 } else {
1586 let expr = if is_unit_return && !has_error {
1587 "()".to_string()
1588 } else {
1589 return_wrap.to_string()
1590 };
1591 (true, expr)
1592 };
1593 crate::template_env::render(
1594 "binding_helpers/async_body_napi.jinja",
1595 minijinja::context! {
1596 result_handling => result_handling,
1597 needs_ok_wrapper => needs_ok_wrapper,
1598 ok_expr => ok_expr,
1599 return_wrap => return_wrap,
1600 },
1601 )
1602 }
1603 AsyncPattern::TokioBlockOn => {
1604 let rt_new = "tokio::runtime::Runtime::new()\
1605 .map_err(|e| extendr_api::Error::Other(e.to_string()))?";
1606 crate::template_env::render(
1607 "binding_helpers/async_body_tokio.jinja",
1608 minijinja::context! {
1609 has_error => has_error,
1610 is_opaque => is_opaque,
1611 is_unit_return => is_unit_return,
1612 core_call => core_call,
1613 return_wrap => return_wrap,
1614 rt_new => rt_new,
1615 },
1616 )
1617 }
1618 AsyncPattern::None => "todo!(\"async not supported by backend\")".to_string(),
1619 };
1620 if inner_clone_line.is_empty() {
1621 pattern_body
1622 } else {
1623 format!("{inner_clone_line}{pattern_body}")
1624 }
1625}
1626
1627pub fn gen_unimplemented_body(
1634 return_type: &TypeRef,
1635 fn_name: &str,
1636 has_error: bool,
1637 cfg: &RustBindingConfig,
1638 params: &[ParamDef],
1639 opaque_types: &AHashSet<String>,
1640) -> String {
1641 let suppress = if params.is_empty() {
1643 String::new()
1644 } else {
1645 let names: Vec<&str> = params.iter().map(|p| p.name.as_str()).collect();
1646 if names.len() == 1 {
1647 format!("let _ = {};\n ", names[0])
1648 } else {
1649 format!("let _ = ({});\n ", names.join(", "))
1650 }
1651 };
1652 let err_msg = format!("Not implemented: {fn_name}");
1653 let body = if has_error {
1654 match cfg.async_pattern {
1656 AsyncPattern::Pyo3FutureIntoPy => {
1657 format!("Err(pyo3::exceptions::PyNotImplementedError::new_err(\"{err_msg}\"))")
1658 }
1659 AsyncPattern::NapiNativeAsync => {
1660 format!("Err(napi::Error::new(napi::Status::GenericFailure, \"{err_msg}\"))")
1661 }
1662 AsyncPattern::WasmNativeAsync => {
1663 format!("Err(JsValue::from_str(\"{err_msg}\"))")
1664 }
1665 _ if cfg.cast_uints_to_i32 => {
1668 format!("Err(extendr_api::Error::Other(\"{err_msg}\".to_string()))")
1669 }
1670 _ => format!("Err(\"{err_msg}\".to_string())"),
1671 }
1672 } else {
1673 match return_type {
1675 TypeRef::Unit => "()".to_string(),
1676 TypeRef::String | TypeRef::Char | TypeRef::Path => format!("String::from(\"[unimplemented: {fn_name}]\")"),
1677 TypeRef::Bytes => "Vec::new()".to_string(),
1678 TypeRef::Primitive(p) => match p {
1679 alef_core::ir::PrimitiveType::Bool => "false".to_string(),
1680 alef_core::ir::PrimitiveType::F32 => "0.0f32".to_string(),
1681 alef_core::ir::PrimitiveType::F64 => "0.0f64".to_string(),
1682 _ => "0".to_string(),
1683 },
1684 TypeRef::Optional(_) => "None".to_string(),
1685 TypeRef::Vec(_) => "Vec::new()".to_string(),
1686 TypeRef::Map(_, _) => "Default::default()".to_string(),
1687 TypeRef::Duration => "0".to_string(),
1688 TypeRef::Named(name) => {
1689 if opaque_types.contains(name.as_str()) {
1693 format!("todo!(\"{err_msg}\")")
1694 } else {
1695 "Default::default()".to_string()
1696 }
1697 }
1698 TypeRef::Json => {
1699 "Default::default()".to_string()
1701 }
1702 }
1703 };
1704 format!("{suppress}{body}")
1705}