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}.into_iter().map(|v| v.clone().into()).collect()")
220 } else {
221 format!("{expr}.into_iter().map(Into::into).collect()")
222 }
223 }
224 TypeRef::Path => {
225 format!("{expr}.into_iter().map(Into::into).collect()")
226 }
227 TypeRef::String => {
228 if returns_ref {
229 format!("{expr}.iter().map(|s| s.to_string()).collect()")
233 } else {
234 expr.to_string()
235 }
236 }
237 TypeRef::Bytes => {
238 if returns_ref {
239 format!("{expr}.iter().map(|b| b.to_vec()).collect()")
240 } else {
241 expr.to_string()
242 }
243 }
244 _ => expr.to_string(),
245 },
246 _ => expr.to_string(),
247 }
248}
249
250pub fn wrap_return(
255 expr: &str,
256 return_type: &TypeRef,
257 type_name: &str,
258 opaque_types: &AHashSet<String>,
259 self_is_opaque: bool,
260 returns_ref: bool,
261 returns_cow: bool,
262) -> String {
263 wrap_return_with_mutex(
264 expr,
265 return_type,
266 type_name,
267 opaque_types,
268 &AHashSet::new(),
269 self_is_opaque,
270 returns_ref,
271 returns_cow,
272 )
273}
274
275pub fn apply_return_newtype_unwrap(expr: &str, return_newtype_wrapper: &Option<String>) -> String {
280 match return_newtype_wrapper {
281 Some(_) => crate::template_env::render(
282 "binding_helpers/return_newtype_unwrap.jinja",
283 minijinja::context! {
284 expr => expr,
285 },
286 )
287 .trim_end_matches('\n')
288 .to_string(),
289 None => expr.to_string(),
290 }
291}
292
293pub fn gen_call_args(params: &[ParamDef], opaque_types: &AHashSet<String>) -> String {
304 params
305 .iter()
306 .enumerate()
307 .map(|(idx, p)| {
308 let promoted = crate::shared::is_promoted_optional(params, idx);
309 let unwrap_suffix = if promoted && p.optional {
314 format!(".expect(\"'{}' is required\")", p.name)
315 } else {
316 String::new()
317 };
318 if let Some(newtype_path) = &p.newtype_wrapper {
321 return if p.optional {
322 format!("{}.map({newtype_path})", p.name)
323 } else if promoted {
324 format!("{newtype_path}({}{})", p.name, unwrap_suffix)
325 } else {
326 format!("{newtype_path}({})", p.name)
327 };
328 }
329 match &p.ty {
330 TypeRef::Named(name) if opaque_types.contains(name.as_str()) => {
331 if p.optional {
333 format!("{}.as_ref().map(|v| &v.inner)", p.name)
334 } else if promoted {
335 format!("{}{}.inner.as_ref()", p.name, unwrap_suffix)
336 } else {
337 format!("&{}.inner", p.name)
338 }
339 }
340 TypeRef::Named(_) => {
341 if p.optional {
342 if p.is_ref {
343 format!("{}.as_ref()", p.name)
346 } else {
347 format!("{}.map(Into::into)", p.name)
348 }
349 } else if promoted {
350 format!("{}{}.into()", p.name, unwrap_suffix)
351 } else {
352 format!("{}.into()", p.name)
353 }
354 }
355 TypeRef::String | TypeRef::Char => {
359 if p.optional {
360 if p.is_ref {
361 format!("{}.as_deref()", p.name)
362 } else {
363 p.name.clone()
364 }
365 } else if promoted {
366 if p.is_ref {
367 format!("&{}{}", p.name, unwrap_suffix)
368 } else {
369 format!("{}{}", p.name, unwrap_suffix)
370 }
371 } else if p.is_ref {
372 format!("&{}", p.name)
373 } else {
374 p.name.clone()
375 }
376 }
377 TypeRef::Path => {
379 if p.optional && p.is_ref {
380 format!("{}.as_deref().map(std::path::Path::new)", p.name)
381 } else if p.optional {
382 format!("{}.map(std::path::PathBuf::from)", p.name)
383 } else if promoted {
384 format!("std::path::PathBuf::from({}{})", p.name, unwrap_suffix)
385 } else if p.is_ref {
386 format!("std::path::Path::new(&{})", p.name)
387 } else {
388 format!("std::path::PathBuf::from({})", p.name)
389 }
390 }
391 TypeRef::Bytes => {
392 if p.optional {
393 if p.is_ref {
394 format!("{}.as_deref()", p.name)
395 } else {
396 p.name.clone()
397 }
398 } else if promoted {
399 if p.is_ref {
402 format!("&{}{}", p.name, unwrap_suffix)
403 } else {
404 format!("{}{}", p.name, unwrap_suffix)
405 }
406 } else {
407 if p.is_ref {
410 format!("&{}", p.name)
411 } else {
412 p.name.clone()
413 }
414 }
415 }
416 TypeRef::Duration => {
418 if p.optional {
419 format!("{}.map(std::time::Duration::from_millis)", p.name)
420 } else if promoted {
421 format!("std::time::Duration::from_millis({}{})", p.name, unwrap_suffix)
422 } else {
423 format!("std::time::Duration::from_millis({})", p.name)
424 }
425 }
426 TypeRef::Json => {
427 if p.optional {
429 format!("{}.as_ref().and_then(|s| serde_json::from_str(s).ok())", p.name)
430 } else if promoted {
431 format!("serde_json::from_str(&{}{}).unwrap_or_default()", p.name, unwrap_suffix)
432 } else {
433 format!("serde_json::from_str(&{}).unwrap_or_default()", p.name)
434 }
435 }
436 TypeRef::Vec(inner) => {
437 if matches!(inner.as_ref(), TypeRef::Named(_)) {
439 if p.optional {
440 if p.is_ref {
441 format!("{}.as_deref()", p.name)
442 } else {
443 p.name.clone()
444 }
445 } else if promoted {
446 if p.is_ref {
447 format!("&{}{}", p.name, unwrap_suffix)
448 } else {
449 format!("{}{}", p.name, unwrap_suffix)
450 }
451 } else if p.is_ref {
452 format!("&{}", p.name)
453 } else {
454 p.name.clone()
455 }
456 } else if promoted {
457 format!("{}{}", p.name, unwrap_suffix)
458 } else if p.is_mut && p.optional {
459 format!("{}.as_deref_mut()", p.name)
460 } else if p.is_mut {
461 format!("&mut {}", p.name)
462 } else if p.is_ref && p.optional {
463 format!("{}.as_deref()", p.name)
464 } else if p.is_ref {
465 format!("&{}", p.name)
466 } else {
467 p.name.clone()
468 }
469 }
470 _ => {
471 if promoted {
472 format!("{}{}", p.name, unwrap_suffix)
473 } else if p.is_mut && p.optional {
474 format!("{}.as_deref_mut()", p.name)
475 } else if p.is_mut {
476 format!("&mut {}", p.name)
477 } else if p.is_ref && p.optional {
478 format!("{}.as_deref()", p.name)
481 } else if p.is_ref {
482 format!("&{}", p.name)
483 } else {
484 p.name.clone()
485 }
486 }
487 }
488 })
489 .collect::<Vec<_>>()
490 .join(", ")
491}
492
493pub fn gen_call_args_cfg(
500 params: &[ParamDef],
501 opaque_types: &AHashSet<String>,
502 cast_uints_to_i32: bool,
503 cast_large_ints_to_f64: bool,
504) -> String {
505 params
506 .iter()
507 .enumerate()
508 .map(|(idx, p)| {
509 let promoted = crate::shared::is_promoted_optional(params, idx);
510 let unwrap_suffix = if promoted && p.optional {
511 format!(".expect(\"'{}' is required\")", p.name)
512 } else {
513 String::new()
514 };
515 if p.newtype_wrapper.is_some() {
517 return gen_call_args(std::slice::from_ref(p), opaque_types);
520 }
521 if let TypeRef::Primitive(prim) = &p.ty {
523 let core_ty = core_prim_str(prim);
524 let needs_cast =
525 (cast_uints_to_i32 && needs_i32_cast(prim)) || (cast_large_ints_to_f64 && needs_f64_cast(prim));
526 if needs_cast {
527 return if p.optional {
528 format!("{}.map(|v| v as {core_ty})", p.name)
529 } else if promoted {
530 format!("({}{}) as {core_ty}", p.name, unwrap_suffix)
531 } else {
532 format!("{} as {core_ty}", p.name)
533 };
534 }
535 }
536 gen_call_args(std::slice::from_ref(p), opaque_types)
538 })
539 .collect::<Vec<_>>()
540 .join(", ")
541}
542
543pub fn gen_call_args_with_let_bindings(params: &[ParamDef], opaque_types: &AHashSet<String>) -> String {
546 params
547 .iter()
548 .enumerate()
549 .map(|(idx, p)| {
550 let promoted = crate::shared::is_promoted_optional(params, idx);
551 let unwrap_suffix = if promoted {
552 format!(".expect(\"'{}' is required\")", p.name)
553 } else {
554 String::new()
555 };
556 if let Some(newtype_path) = &p.newtype_wrapper {
558 return if p.optional {
559 format!("{}.map({newtype_path})", p.name)
560 } else if promoted {
561 format!("{newtype_path}({}{})", p.name, unwrap_suffix)
562 } else {
563 format!("{newtype_path}({})", p.name)
564 };
565 }
566 match &p.ty {
567 TypeRef::Named(name) if opaque_types.contains(name.as_str()) => {
568 if p.optional {
569 format!("{}.as_ref().map(|v| &v.inner)", p.name)
570 } else if promoted {
571 format!("{}{}.inner.as_ref()", p.name, unwrap_suffix)
572 } else {
573 format!("&{}.inner", p.name)
574 }
575 }
576 TypeRef::Named(_) => {
577 if p.optional && p.is_ref {
578 format!("{}_core", p.name)
580 } else if p.is_ref {
581 format!("&{}_core", p.name)
583 } else {
584 format!("{}_core", p.name)
585 }
586 }
587 TypeRef::String | TypeRef::Char => {
588 if p.optional {
589 if p.is_ref {
590 format!("{}.as_deref()", p.name)
591 } else {
592 p.name.clone()
593 }
594 } else if promoted {
595 if p.is_ref {
596 format!("&{}{}", p.name, unwrap_suffix)
597 } else {
598 format!("{}{}", p.name, unwrap_suffix)
599 }
600 } else if p.is_ref {
601 format!("&{}", p.name)
602 } else {
603 p.name.clone()
604 }
605 }
606 TypeRef::Path => {
607 if promoted {
608 format!("std::path::PathBuf::from({}{})", p.name, unwrap_suffix)
609 } else if p.optional && p.is_ref {
610 format!("{}.as_deref().map(std::path::Path::new)", p.name)
611 } else if p.optional {
612 format!("{}.map(std::path::PathBuf::from)", p.name)
613 } else if p.is_ref {
614 format!("std::path::Path::new(&{})", p.name)
615 } else {
616 format!("std::path::PathBuf::from({})", p.name)
617 }
618 }
619 TypeRef::Bytes => {
620 if p.optional {
621 if p.is_ref {
622 format!("{}.as_deref()", p.name)
623 } else {
624 p.name.clone()
625 }
626 } else if promoted {
627 if p.is_ref {
630 format!("&{}{}", p.name, unwrap_suffix)
631 } else {
632 format!("{}{}", p.name, unwrap_suffix)
633 }
634 } else {
635 if p.is_ref {
638 format!("&{}", p.name)
639 } else {
640 p.name.clone()
641 }
642 }
643 }
644 TypeRef::Duration => {
645 if p.optional {
646 format!("{}.map(std::time::Duration::from_millis)", p.name)
647 } else if promoted {
648 format!("std::time::Duration::from_millis({}{})", p.name, unwrap_suffix)
649 } else {
650 format!("std::time::Duration::from_millis({})", p.name)
651 }
652 }
653 TypeRef::Vec(inner) => {
654 if matches!(inner.as_ref(), TypeRef::String) && p.sanitized && p.original_type.is_some() {
657 if p.optional && p.is_ref {
658 format!("{}_core.as_deref()", p.name)
659 } else if p.optional {
660 format!("{}_core", p.name)
661 } else if p.is_ref {
662 format!("&{}_core", p.name)
663 } else {
664 format!("{}_core", p.name)
665 }
666 } else if matches!(inner.as_ref(), TypeRef::Named(_)) {
667 if p.optional && p.is_ref {
669 format!("{}_core.as_deref()", p.name)
671 } else if p.optional {
672 format!("{}_core", p.name)
674 } else if p.is_ref {
675 format!("&{}_core", p.name)
676 } else {
677 format!("{}_core", p.name)
678 }
679 } else if matches!(inner.as_ref(), TypeRef::String | TypeRef::Char) && p.is_ref {
680 if p.optional {
683 format!("{}.as_deref()", p.name)
684 } else {
685 format!("&{}_refs", p.name)
686 }
687 } else if promoted {
688 format!("{}{}", p.name, unwrap_suffix)
689 } else if p.is_ref && p.optional {
690 format!("{}.as_deref()", p.name)
691 } else if p.is_ref {
692 format!("&{}", p.name)
693 } else {
694 p.name.clone()
695 }
696 }
697 _ => {
698 if promoted {
699 format!("{}{}", p.name, unwrap_suffix)
700 } else if p.is_ref && p.optional {
701 format!("{}.as_deref()", p.name)
702 } else if p.is_ref {
703 format!("&{}", p.name)
704 } else {
705 p.name.clone()
706 }
707 }
708 }
709 })
710 .collect::<Vec<_>>()
711 .join(", ")
712}
713
714pub fn gen_named_let_bindings_pub(params: &[ParamDef], opaque_types: &AHashSet<String>, core_import: &str) -> String {
716 gen_named_let_bindings(params, opaque_types, core_import)
717}
718
719pub fn gen_named_let_bindings_no_promote(
722 params: &[ParamDef],
723 opaque_types: &AHashSet<String>,
724 core_import: &str,
725) -> String {
726 gen_named_let_bindings_inner(params, opaque_types, core_import, false)
727}
728
729pub(super) fn gen_named_let_bindings(
730 params: &[ParamDef],
731 opaque_types: &AHashSet<String>,
732 core_import: &str,
733) -> String {
734 gen_named_let_bindings_inner(params, opaque_types, core_import, true)
735}
736
737pub(super) fn gen_named_let_bindings_by_ref(
741 params: &[ParamDef],
742 opaque_types: &AHashSet<String>,
743 core_import: &str,
744) -> String {
745 let mut bindings = String::new();
746 for (idx, p) in params.iter().enumerate() {
747 match &p.ty {
748 TypeRef::Named(name) if !opaque_types.contains(name.as_str()) => {
749 let promoted = crate::shared::is_promoted_optional(params, idx);
750 let core_type_path = format!("{core_import}::{name}");
751 let binding = if p.optional {
752 crate::template_env::render(
753 "binding_helpers/named_let_binding_by_ref_optional.jinja",
754 minijinja::context! {
755 name => &p.name,
756 core_type_path => &core_type_path,
757 },
758 )
759 } else if promoted {
760 crate::template_env::render(
761 "binding_helpers/named_let_binding_by_ref_promoted.jinja",
762 minijinja::context! {
763 name => &p.name,
764 core_type_path => &core_type_path,
765 },
766 )
767 } else {
768 crate::template_env::render(
769 "binding_helpers/named_let_binding_by_ref_simple.jinja",
770 minijinja::context! {
771 name => &p.name,
772 core_type_path => &core_type_path,
773 },
774 )
775 };
776 bindings.push_str(&binding);
777 bindings.push_str("\n ");
778 }
779 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if !opaque_types.contains(n.as_str())) => {
780 let binding = if p.optional {
781 crate::template_env::render(
782 "binding_helpers/vec_named_let_binding_by_ref_optional.jinja",
783 minijinja::context! {
784 name => &p.name,
785 },
786 )
787 } else {
788 let promoted = crate::shared::is_promoted_optional(params, idx);
789 if promoted {
790 crate::template_env::render(
791 "binding_helpers/vec_named_let_binding_by_ref_promoted.jinja",
792 minijinja::context! {
793 name => &p.name,
794 },
795 )
796 } else {
797 crate::template_env::render(
798 "binding_helpers/vec_named_let_binding_by_ref_simple.jinja",
799 minijinja::context! {
800 name => &p.name,
801 },
802 )
803 }
804 };
805 bindings.push_str(&binding);
806 bindings.push_str("\n ");
807 }
808 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::String | TypeRef::Char) && p.is_ref => {
809 let binding = if p.optional {
810 crate::template_env::render(
811 "binding_helpers/vec_string_refs_binding_optional.jinja",
812 minijinja::context! {
813 name => &p.name,
814 },
815 )
816 } else {
817 crate::template_env::render(
818 "binding_helpers/vec_string_refs_binding_simple.jinja",
819 minijinja::context! {
820 name => &p.name,
821 },
822 )
823 };
824 bindings.push_str(&binding);
825 bindings.push_str("\n ");
826 }
827 _ => {}
828 }
829 }
830 bindings
831}
832
833fn gen_named_let_bindings_inner(
834 params: &[ParamDef],
835 opaque_types: &AHashSet<String>,
836 core_import: &str,
837 promote: bool,
838) -> String {
839 let mut bindings = String::new();
840 for (idx, p) in params.iter().enumerate() {
841 match &p.ty {
842 TypeRef::Named(name) if !opaque_types.contains(name.as_str()) => {
843 let promoted = promote && crate::shared::is_promoted_optional(params, idx);
844 let core_type_path = format!("{}::{}", core_import, name);
845 let binding = if p.optional {
846 if p.is_ref {
847 crate::template_env::render(
848 "binding_helpers/named_let_binding_optional_ref.jinja",
849 minijinja::context! {
850 name => &p.name,
851 core_type_path => &core_type_path,
852 },
853 )
854 } else {
855 crate::template_env::render(
856 "binding_helpers/named_let_binding_optional.jinja",
857 minijinja::context! {
858 name => &p.name,
859 core_type_path => &core_type_path,
860 },
861 )
862 }
863 } else if promoted {
864 crate::template_env::render(
865 "binding_helpers/named_let_binding_promoted.jinja",
866 minijinja::context! {
867 name => &p.name,
868 core_type_path => &core_type_path,
869 },
870 )
871 } else {
872 crate::template_env::render(
873 "binding_helpers/named_let_binding_simple.jinja",
874 minijinja::context! {
875 name => &p.name,
876 core_type_path => &core_type_path,
877 },
878 )
879 };
880 bindings.push_str(&binding);
881 bindings.push_str("\n ");
882 }
883 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if !opaque_types.contains(n.as_str())) => {
884 let promoted = promote && crate::shared::is_promoted_optional(params, idx);
885 let binding = if p.optional && p.is_ref {
886 crate::template_env::render(
887 "binding_helpers/vec_named_let_binding_optional.jinja",
888 minijinja::context! {
889 name => &p.name,
890 },
891 )
892 } else if p.optional {
893 crate::template_env::render(
894 "binding_helpers/vec_named_let_binding_optional_no_ref.jinja",
895 minijinja::context! {
896 name => &p.name,
897 },
898 )
899 } else if promoted {
900 crate::template_env::render(
901 "binding_helpers/vec_named_let_binding_promoted.jinja",
902 minijinja::context! {
903 name => &p.name,
904 },
905 )
906 } else {
907 crate::template_env::render(
908 "binding_helpers/vec_named_let_binding_simple.jinja",
909 minijinja::context! {
910 name => &p.name,
911 },
912 )
913 };
914 bindings.push_str(&binding);
915 bindings.push_str("\n ");
916 }
917 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::String | TypeRef::Char) && p.is_ref => {
920 let binding = if p.optional {
921 crate::template_env::render(
922 "binding_helpers/vec_string_refs_binding_optional.jinja",
923 minijinja::context! {
924 name => &p.name,
925 },
926 )
927 } else {
928 crate::template_env::render(
929 "binding_helpers/vec_string_refs_binding_simple.jinja",
930 minijinja::context! {
931 name => &p.name,
932 },
933 )
934 };
935 bindings.push_str(&binding);
936 bindings.push_str("\n ");
937 }
938 TypeRef::Vec(inner)
940 if matches!(inner.as_ref(), TypeRef::String) && p.sanitized && p.original_type.is_some() =>
941 {
942 let template = if p.optional {
943 "binding_helpers/sanitized_vec_string_filter_optional.jinja"
944 } else {
945 "binding_helpers/sanitized_vec_string_filter_simple.jinja"
946 };
947 bindings.push_str(&crate::template_env::render(
948 template,
949 minijinja::context! {
950 name => &p.name,
951 },
952 ));
953 }
954 _ => {}
955 }
956 }
957 bindings
958}
959
960pub fn gen_serde_let_bindings(
967 params: &[ParamDef],
968 opaque_types: &AHashSet<String>,
969 core_import: &str,
970 err_conv: &str,
971 indent: &str,
972) -> String {
973 let mut bindings = String::new();
974 for (idx, p) in params.iter().enumerate() {
975 let promoted = crate::shared::is_promoted_optional(params, idx);
976 match &p.ty {
977 TypeRef::Named(name) if !opaque_types.contains(name.as_str()) => {
978 let core_path = format!("{}::{}", core_import, name);
979 if p.optional {
980 bindings.push_str(&crate::template_env::render(
981 "binding_helpers/serde_named_let_binding_optional.jinja",
982 minijinja::context! {
983 name => &p.name,
984 core_path => core_path,
985 err_conv => err_conv,
986 indent => indent,
987 },
988 ));
989 } else if promoted {
990 bindings.push_str(&crate::template_env::render(
994 "binding_helpers/serde_named_let_binding_promoted.jinja",
995 minijinja::context! {
996 name => &p.name,
997 core_path => core_path,
998 err_conv => err_conv,
999 indent => indent,
1000 },
1001 ));
1002 } else {
1003 bindings.push_str(&crate::template_env::render(
1004 "binding_helpers/serde_named_let_binding_simple.jinja",
1005 minijinja::context! {
1006 name => &p.name,
1007 core_path => core_path,
1008 err_conv => err_conv,
1009 indent => indent,
1010 },
1011 ));
1012 }
1013 }
1014 TypeRef::Vec(inner) => {
1015 if let TypeRef::Named(name) = inner.as_ref() {
1016 if !opaque_types.contains(name.as_str()) {
1017 let core_path = format!("{}::{}", core_import, name);
1018 if p.optional {
1019 bindings.push_str(&crate::template_env::render(
1020 "binding_helpers/serde_vec_named_optional.jinja",
1021 minijinja::context! {
1022 name => &p.name,
1023 core_path => core_path,
1024 err_conv => err_conv,
1025 indent => indent,
1026 },
1027 ));
1028 } else {
1029 bindings.push_str(&crate::template_env::render(
1030 "binding_helpers/serde_vec_named_simple.jinja",
1031 minijinja::context! {
1032 name => &p.name,
1033 core_path => core_path,
1034 err_conv => err_conv,
1035 indent => indent,
1036 },
1037 ));
1038 }
1039 }
1040 } else if matches!(inner.as_ref(), TypeRef::String) && p.sanitized && p.original_type.is_some() {
1041 let template = if p.optional {
1044 "binding_helpers/serde_sanitized_vec_string_optional.jinja"
1045 } else {
1046 "binding_helpers/serde_sanitized_vec_string_simple.jinja"
1047 };
1048 bindings.push_str(&crate::template_env::render(
1049 template,
1050 minijinja::context! {
1051 name => &p.name,
1052 err_conv => err_conv,
1053 indent => indent,
1054 },
1055 ));
1056 }
1057 }
1058 _ => {}
1059 }
1060 }
1061 bindings
1062}
1063
1064pub fn has_named_params(params: &[ParamDef], opaque_types: &AHashSet<String>) -> bool {
1069 params.iter().any(|p| match &p.ty {
1070 TypeRef::Named(name) if !opaque_types.contains(name.as_str()) => true,
1071 TypeRef::Vec(inner) => {
1072 matches!(inner.as_ref(), TypeRef::Named(name) if !opaque_types.contains(name.as_str()))
1076 || (matches!(inner.as_ref(), TypeRef::String | TypeRef::Char) && p.is_ref)
1077 || (matches!(inner.as_ref(), TypeRef::String) && p.sanitized && p.original_type.is_some())
1078 }
1079 _ => false,
1080 })
1081}
1082
1083pub fn is_simple_non_opaque_param(ty: &TypeRef) -> bool {
1086 match ty {
1087 TypeRef::Primitive(_)
1088 | TypeRef::String
1089 | TypeRef::Char
1090 | TypeRef::Bytes
1091 | TypeRef::Path
1092 | TypeRef::Unit
1093 | TypeRef::Duration => true,
1094 TypeRef::Optional(inner) => is_simple_non_opaque_param(inner),
1095 _ => false,
1096 }
1097}
1098
1099pub fn gen_lossy_binding_to_core_fields(
1112 typ: &TypeDef,
1113 core_import: &str,
1114 option_duration_on_defaults: bool,
1115 opaque_types: &AHashSet<String>,
1116 cast_uints_to_i32: bool,
1117 cast_large_ints_to_f64: bool,
1118 skip_types: &[String],
1119) -> String {
1120 gen_lossy_binding_to_core_fields_inner(
1121 typ,
1122 core_import,
1123 false,
1124 option_duration_on_defaults,
1125 opaque_types,
1126 cast_uints_to_i32,
1127 cast_large_ints_to_f64,
1128 skip_types,
1129 )
1130}
1131
1132pub fn gen_lossy_binding_to_core_fields_mut(
1134 typ: &TypeDef,
1135 core_import: &str,
1136 option_duration_on_defaults: bool,
1137 opaque_types: &AHashSet<String>,
1138 cast_uints_to_i32: bool,
1139 cast_large_ints_to_f64: bool,
1140 skip_types: &[String],
1141) -> String {
1142 gen_lossy_binding_to_core_fields_inner(
1143 typ,
1144 core_import,
1145 true,
1146 option_duration_on_defaults,
1147 opaque_types,
1148 cast_uints_to_i32,
1149 cast_large_ints_to_f64,
1150 skip_types,
1151 )
1152}
1153
1154#[allow(clippy::too_many_arguments)]
1155fn gen_lossy_binding_to_core_fields_inner(
1156 typ: &TypeDef,
1157 core_import: &str,
1158 needs_mut: bool,
1159 option_duration_on_defaults: bool,
1160 opaque_types: &AHashSet<String>,
1161 cast_uints_to_i32: bool,
1162 cast_large_ints_to_f64: bool,
1163 skip_types: &[String],
1164) -> String {
1165 let core_path = crate::conversions::core_type_path(typ, core_import);
1166 let mut_kw = if needs_mut { "mut " } else { "" };
1167 let allow = if typ.has_stripped_cfg_fields {
1172 "#[allow(clippy::needless_update)]\n "
1173 } else {
1174 ""
1175 };
1176 let mut out = format!("{allow}let {mut_kw}core_self = {core_path} {{\n");
1177 for field in &typ.fields {
1178 if field.binding_excluded {
1179 out.push_str(&crate::template_env::render(
1180 "binding_helpers/struct_field_default.jinja",
1181 minijinja::context! {
1182 name => &field.name,
1183 },
1184 ));
1185 continue;
1186 }
1187 if field.cfg.is_some() {
1190 continue;
1191 }
1192 let name = &field.name;
1193 if field.sanitized && field.core_wrapper != CoreWrapper::Cow {
1194 out.push_str(&crate::template_env::render(
1195 "binding_helpers/struct_field_default.jinja",
1196 minijinja::context! {
1197 name => &field.name,
1198 },
1199 ));
1200 out.push('\n');
1201 continue;
1202 }
1203 let is_opaque_named = match &field.ty {
1208 TypeRef::Named(n) => opaque_types.contains(n.as_str()),
1209 TypeRef::Optional(inner) => {
1210 matches!(inner.as_ref(), TypeRef::Named(n) if opaque_types.contains(n.as_str()))
1211 }
1212 _ => false,
1213 };
1214 if is_opaque_named {
1215 out.push_str(&crate::template_env::render(
1216 "binding_helpers/struct_field_default.jinja",
1217 minijinja::context! {
1218 name => &field.name,
1219 },
1220 ));
1221 out.push('\n');
1222 continue;
1223 }
1224 let is_skip_named = match &field.ty {
1227 TypeRef::Named(n) => skip_types.contains(n),
1228 TypeRef::Optional(inner) => {
1229 matches!(inner.as_ref(), TypeRef::Named(n) if skip_types.contains(n))
1230 }
1231 _ => false,
1232 };
1233 if is_skip_named {
1234 out.push_str(&crate::template_env::render(
1235 "binding_helpers/default_field.jinja",
1236 minijinja::context! {
1237 name => &name,
1238 },
1239 ));
1240 continue;
1241 }
1242 let expr = match &field.ty {
1243 TypeRef::Primitive(p) if cast_uints_to_i32 && needs_i32_cast(p) => {
1244 let core_ty = core_prim_str(p);
1245 if field.optional {
1246 format!("self.{name}.map(|v| v as {core_ty})")
1247 } else {
1248 format!("self.{name} as {core_ty}")
1249 }
1250 }
1251 TypeRef::Primitive(p) if cast_large_ints_to_f64 && needs_f64_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(_) => format!("self.{name}"),
1260 TypeRef::Duration => {
1261 if field.optional {
1262 format!("self.{name}.map(std::time::Duration::from_millis)")
1263 } else if option_duration_on_defaults && typ.has_default {
1264 format!("self.{name}.map(std::time::Duration::from_millis).unwrap_or_default()")
1269 } else {
1270 format!("std::time::Duration::from_millis(self.{name})")
1271 }
1272 }
1273 TypeRef::String => {
1274 if field.core_wrapper == CoreWrapper::Cow {
1275 format!("self.{name}.clone().into()")
1276 } else {
1277 format!("self.{name}.clone()")
1278 }
1279 }
1280 TypeRef::Bytes => {
1284 if field.core_wrapper == CoreWrapper::Bytes {
1285 format!("self.{name}.clone().into()")
1286 } else {
1287 format!("self.{name}.clone()")
1288 }
1289 }
1290 TypeRef::Char => {
1291 if field.optional {
1292 format!("self.{name}.as_ref().and_then(|s| s.chars().next())")
1293 } else {
1294 format!("self.{name}.chars().next().unwrap_or('*')")
1295 }
1296 }
1297 TypeRef::Path => {
1298 if field.optional {
1299 format!("self.{name}.clone().map(Into::into)")
1300 } else {
1301 format!("self.{name}.clone().into()")
1302 }
1303 }
1304 TypeRef::Named(_) => {
1305 if field.optional {
1306 format!("self.{name}.clone().map(Into::into)")
1307 } else {
1308 format!("self.{name}.clone().into()")
1309 }
1310 }
1311 TypeRef::Vec(inner) => match inner.as_ref() {
1312 TypeRef::Named(_) => {
1313 if field.optional {
1314 format!("self.{name}.clone().map(|v| v.into_iter().map(Into::into).collect())")
1316 } else {
1317 format!("self.{name}.clone().into_iter().map(Into::into).collect()")
1318 }
1319 }
1320 TypeRef::Primitive(p) if cast_uints_to_i32 && needs_i32_cast(p) => {
1322 let core_ty = core_prim_str(p);
1323 if field.optional {
1324 format!("self.{name}.clone().map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
1325 } else {
1326 format!("self.{name}.clone().into_iter().map(|v| v as {core_ty}).collect()")
1327 }
1328 }
1329 TypeRef::Primitive(p) if cast_large_ints_to_f64 && needs_f64_cast(p) => {
1331 let core_ty = core_prim_str(p);
1332 if field.optional {
1333 format!("self.{name}.clone().map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
1334 } else {
1335 format!("self.{name}.clone().into_iter().map(|v| v as {core_ty}).collect()")
1336 }
1337 }
1338 _ => format!("self.{name}.clone()"),
1339 },
1340 TypeRef::Optional(inner) => {
1341 let base = match inner.as_ref() {
1345 TypeRef::Named(_) => {
1346 format!("self.{name}.clone().map(Into::into)")
1347 }
1348 TypeRef::Duration => {
1349 format!("self.{name}.map(|v| std::time::Duration::from_millis(v as u64))")
1350 }
1351 TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_)) => {
1352 format!("self.{name}.clone().map(|v| v.into_iter().map(Into::into).collect())")
1353 }
1354 TypeRef::Vec(vi) => match vi.as_ref() {
1356 TypeRef::Primitive(p) if cast_uints_to_i32 && needs_i32_cast(p) => {
1357 let core_ty = core_prim_str(p);
1358 format!("self.{name}.clone().map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
1359 }
1360 TypeRef::Primitive(p) if cast_large_ints_to_f64 && needs_f64_cast(p) => {
1362 let core_ty = core_prim_str(p);
1363 format!("self.{name}.clone().map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
1364 }
1365 _ => format!("self.{name}.clone()"),
1366 },
1367 _ => format!("self.{name}.clone()"),
1368 };
1369 if field.optional {
1370 format!("({base}).map(Some)")
1371 } else {
1372 base
1373 }
1374 }
1375 TypeRef::Map(_, v) => match v.as_ref() {
1376 TypeRef::Json => {
1377 if field.optional {
1382 format!(
1383 "self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| \
1384 (k.into(), serde_json::from_str(&v).unwrap_or(serde_json::Value::String(v)))).collect())"
1385 )
1386 } else {
1387 format!(
1388 "self.{name}.clone().into_iter().map(|(k, v)| \
1389 (k.into(), serde_json::from_str(&v).unwrap_or(serde_json::Value::String(v)))).collect()"
1390 )
1391 }
1392 }
1393 TypeRef::Named(_) => {
1396 if field.optional {
1397 format!(
1398 "self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())"
1399 )
1400 } else {
1401 format!("self.{name}.clone().into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
1402 }
1403 }
1404 TypeRef::Primitive(p) if cast_uints_to_i32 && needs_i32_cast(p) => {
1406 let core_ty = core_prim_str(p);
1407 if field.optional {
1408 format!(
1409 "self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| (k.into(), v as {core_ty})).collect())"
1410 )
1411 } else {
1412 format!("self.{name}.clone().into_iter().map(|(k, v)| (k.into(), v as {core_ty})).collect()")
1413 }
1414 }
1415 TypeRef::Primitive(p) if cast_large_ints_to_f64 && needs_f64_cast(p) => {
1417 let core_ty = core_prim_str(p);
1418 if field.optional {
1419 format!(
1420 "self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| (k.into(), v as {core_ty})).collect())"
1421 )
1422 } else {
1423 format!("self.{name}.clone().into_iter().map(|(k, v)| (k.into(), v as {core_ty})).collect()")
1424 }
1425 }
1426 _ => {
1428 if field.optional {
1429 format!("self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
1430 } else {
1431 format!("self.{name}.clone().into_iter().map(|(k, v)| (k.into(), v)).collect()")
1432 }
1433 }
1434 },
1435 TypeRef::Unit => format!("self.{name}.clone()"),
1436 TypeRef::Json => {
1437 if field.optional {
1439 format!("self.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())")
1440 } else {
1441 format!("serde_json::from_str(&self.{name}).unwrap_or_default()")
1442 }
1443 }
1444 };
1445 let expr = if let Some(newtype_path) = &field.newtype_wrapper {
1450 match &field.ty {
1451 TypeRef::Optional(_) => format!("({expr}).map({newtype_path})"),
1452 TypeRef::Vec(_) => format!("({expr}).into_iter().map({newtype_path}).collect::<Vec<_>>()"),
1453 _ if field.optional => format!("({expr}).map({newtype_path})"),
1454 _ => format!("{newtype_path}({expr})"),
1455 }
1456 } else {
1457 expr
1458 };
1459 out.push_str(&crate::template_env::render(
1460 "binding_helpers/struct_field_line.jinja",
1461 minijinja::context! {
1462 name => &field.name,
1463 expr => &expr,
1464 },
1465 ));
1466 out.push('\n');
1467 }
1468 if typ.has_stripped_cfg_fields {
1470 out.push_str(" ..Default::default()\n");
1471 }
1472 out.push_str(" };\n ");
1473 out
1474}
1475
1476#[allow(clippy::too_many_arguments)]
1491pub fn gen_async_body(
1492 core_call: &str,
1493 cfg: &RustBindingConfig,
1494 has_error: bool,
1495 return_wrap: &str,
1496 is_opaque: bool,
1497 inner_clone_line: &str,
1498 is_unit_return: bool,
1499 return_type: Option<&str>,
1500) -> String {
1501 let pattern_body = match cfg.async_pattern {
1502 AsyncPattern::Pyo3FutureIntoPy => {
1503 let result_handling = if has_error {
1504 format!(
1505 "let result = {core_call}.await\n \
1506 .map_err(|e| PyErr::new::<PyRuntimeError, _>(e.to_string()))?;"
1507 )
1508 } else if is_unit_return {
1509 format!("{core_call}.await;")
1510 } else {
1511 format!("let result = {core_call}.await;")
1512 };
1513 let (ok_expr, extra_binding) = if is_unit_return && !has_error {
1514 ("()".to_string(), String::new())
1515 } else if return_wrap.contains(".into()") || return_wrap.contains("::from(") {
1516 let wrapped_var = "wrapped_result";
1520 let binding = if let Some(ret_type) = return_type {
1521 format!("let {wrapped_var}: {ret_type} = {return_wrap};\n ")
1523 } else {
1524 format!("let {wrapped_var} = {return_wrap};\n ")
1525 };
1526 (wrapped_var.to_string(), binding)
1527 } else {
1528 (return_wrap.to_string(), String::new())
1529 };
1530 crate::template_env::render(
1531 "binding_helpers/async_body_pyo3.jinja",
1532 minijinja::context! {
1533 result_handling => result_handling,
1534 extra_binding => extra_binding,
1535 ok_expr => ok_expr,
1536 },
1537 )
1538 }
1539 AsyncPattern::WasmNativeAsync => {
1540 let result_handling = if has_error {
1541 format!(
1542 "let result = {core_call}.await\n \
1543 .map_err(|e| JsValue::from_str(&e.to_string()))?;"
1544 )
1545 } else if is_unit_return {
1546 format!("{core_call}.await;")
1547 } else {
1548 format!("let result = {core_call}.await;")
1549 };
1550 let ok_expr = if is_unit_return && !has_error {
1551 "()"
1552 } else {
1553 return_wrap
1554 };
1555 crate::template_env::render(
1556 "binding_helpers/async_body_wasm.jinja",
1557 minijinja::context! {
1558 result_handling => result_handling,
1559 ok_expr => ok_expr,
1560 },
1561 )
1562 }
1563 AsyncPattern::NapiNativeAsync => {
1564 let result_handling = if has_error {
1565 format!(
1566 "let result = {core_call}.await\n \
1567 .map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))?;"
1568 )
1569 } else if is_unit_return {
1570 format!("{core_call}.await;")
1571 } else {
1572 format!("let result = {core_call}.await;")
1573 };
1574 let (needs_ok_wrapper, ok_expr) = if !has_error && !is_unit_return {
1575 (false, return_wrap.to_string())
1577 } else {
1578 let expr = if is_unit_return && !has_error {
1579 "()".to_string()
1580 } else {
1581 return_wrap.to_string()
1582 };
1583 (true, expr)
1584 };
1585 crate::template_env::render(
1586 "binding_helpers/async_body_napi.jinja",
1587 minijinja::context! {
1588 result_handling => result_handling,
1589 needs_ok_wrapper => needs_ok_wrapper,
1590 ok_expr => ok_expr,
1591 return_wrap => return_wrap,
1592 },
1593 )
1594 }
1595 AsyncPattern::TokioBlockOn => {
1596 let rt_new = "tokio::runtime::Runtime::new()\
1597 .map_err(|e| extendr_api::Error::Other(e.to_string()))?";
1598 crate::template_env::render(
1599 "binding_helpers/async_body_tokio.jinja",
1600 minijinja::context! {
1601 has_error => has_error,
1602 is_opaque => is_opaque,
1603 is_unit_return => is_unit_return,
1604 core_call => core_call,
1605 return_wrap => return_wrap,
1606 rt_new => rt_new,
1607 },
1608 )
1609 }
1610 AsyncPattern::None => "todo!(\"async not supported by backend\")".to_string(),
1611 };
1612 if inner_clone_line.is_empty() {
1613 pattern_body
1614 } else {
1615 format!("{inner_clone_line}{pattern_body}")
1616 }
1617}
1618
1619pub fn gen_unimplemented_body(
1626 return_type: &TypeRef,
1627 fn_name: &str,
1628 has_error: bool,
1629 cfg: &RustBindingConfig,
1630 params: &[ParamDef],
1631 opaque_types: &AHashSet<String>,
1632) -> String {
1633 let suppress = if params.is_empty() {
1635 String::new()
1636 } else {
1637 let names: Vec<&str> = params.iter().map(|p| p.name.as_str()).collect();
1638 if names.len() == 1 {
1639 format!("let _ = {};\n ", names[0])
1640 } else {
1641 format!("let _ = ({});\n ", names.join(", "))
1642 }
1643 };
1644 let err_msg = format!("Not implemented: {fn_name}");
1645 let body = if has_error {
1646 match cfg.async_pattern {
1648 AsyncPattern::Pyo3FutureIntoPy => {
1649 format!("Err(pyo3::exceptions::PyNotImplementedError::new_err(\"{err_msg}\"))")
1650 }
1651 AsyncPattern::NapiNativeAsync => {
1652 format!("Err(napi::Error::new(napi::Status::GenericFailure, \"{err_msg}\"))")
1653 }
1654 AsyncPattern::WasmNativeAsync => {
1655 format!("Err(JsValue::from_str(\"{err_msg}\"))")
1656 }
1657 _ if cfg.cast_uints_to_i32 => {
1660 format!("Err(extendr_api::Error::Other(\"{err_msg}\".to_string()))")
1661 }
1662 _ => format!("Err(\"{err_msg}\".to_string())"),
1663 }
1664 } else {
1665 match return_type {
1667 TypeRef::Unit => "()".to_string(),
1668 TypeRef::String | TypeRef::Char | TypeRef::Path => format!("String::from(\"[unimplemented: {fn_name}]\")"),
1669 TypeRef::Bytes => "Vec::new()".to_string(),
1670 TypeRef::Primitive(p) => match p {
1671 alef_core::ir::PrimitiveType::Bool => "false".to_string(),
1672 alef_core::ir::PrimitiveType::F32 => "0.0f32".to_string(),
1673 alef_core::ir::PrimitiveType::F64 => "0.0f64".to_string(),
1674 _ => "0".to_string(),
1675 },
1676 TypeRef::Optional(_) => "None".to_string(),
1677 TypeRef::Vec(_) => "Vec::new()".to_string(),
1678 TypeRef::Map(_, _) => "Default::default()".to_string(),
1679 TypeRef::Duration => "0".to_string(),
1680 TypeRef::Named(name) => {
1681 if opaque_types.contains(name.as_str()) {
1685 format!("todo!(\"{err_msg}\")")
1686 } else {
1687 "Default::default()".to_string()
1688 }
1689 }
1690 TypeRef::Json => {
1691 "Default::default()".to_string()
1693 }
1694 }
1695 };
1696 format!("{suppress}{body}")
1697}