1use crate::conversions::helpers::{core_prim_str, needs_f64_cast, needs_i32_cast};
2use crate::generators::{AsyncPattern, RustBindingConfig};
3use ahash::AHashSet;
4use alef_core::ir::{CoreWrapper, ParamDef, TypeDef, TypeRef};
5use std::fmt::Write;
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
24#[allow(clippy::too_many_arguments)]
38pub fn wrap_return_with_mutex(
39 expr: &str,
40 return_type: &TypeRef,
41 type_name: &str,
42 opaque_types: &AHashSet<String>,
43 mutex_types: &AHashSet<String>,
44 self_is_opaque: bool,
45 returns_ref: bool,
46 returns_cow: bool,
47) -> String {
48 let self_arc = arc_wrap("", type_name, mutex_types); let _ = self_arc; match return_type {
51 TypeRef::Named(n) if n == type_name && self_is_opaque => {
52 let inner = if returns_cow {
53 format!("{expr}.into_owned()")
54 } else if returns_ref {
55 format!("{expr}.clone()")
56 } else {
57 expr.to_string()
58 };
59 format!("Self {{ inner: {} }}", arc_wrap(&inner, type_name, mutex_types))
60 }
61 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
62 let inner = if returns_cow {
63 format!("{expr}.into_owned()")
64 } else if returns_ref {
65 format!("{expr}.clone()")
66 } else {
67 expr.to_string()
68 };
69 format!("{n} {{ inner: {} }}", arc_wrap(&inner, n, mutex_types))
70 }
71 TypeRef::Named(_) => {
72 if returns_cow {
79 format!("{expr}.into_owned().into()")
80 } else if returns_ref {
81 format!("{expr}.clone().into()")
82 } else {
83 format!("{expr}.into()")
84 }
85 }
86 TypeRef::String => {
88 if returns_ref {
89 format!("{expr}.into()")
90 } else {
91 expr.to_string()
92 }
93 }
94 TypeRef::Bytes => format!("{expr}.to_vec()"),
97 TypeRef::Path => format!("{expr}.to_string_lossy().to_string()"),
99 TypeRef::Duration => format!("{expr}.as_millis() as u64"),
101 TypeRef::Json => format!("{expr}.to_string()"),
103 TypeRef::Optional(inner) => match inner.as_ref() {
105 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
106 let wrap = arc_wrap("v", n, mutex_types);
107 if returns_ref {
108 format!(
109 "{expr}.map(|v| {n} {{ inner: {} }})",
110 arc_wrap("v.clone()", n, mutex_types)
111 )
112 } else {
113 format!("{expr}.map(|v| {n} {{ inner: {wrap} }})")
114 }
115 }
116 TypeRef::Named(_) => {
117 if returns_ref {
118 format!("{expr}.map(|v| v.clone().into())")
119 } else {
120 format!("{expr}.map(Into::into)")
121 }
122 }
123 TypeRef::Path => {
124 format!("{expr}.map(Into::into)")
125 }
126 TypeRef::String | TypeRef::Bytes => {
127 if returns_ref {
128 format!("{expr}.map(Into::into)")
129 } else {
130 expr.to_string()
131 }
132 }
133 TypeRef::Duration => format!("{expr}.map(|d| d.as_millis() as u64)"),
134 TypeRef::Json => format!("{expr}.map(ToString::to_string)"),
135 TypeRef::Vec(vec_inner) => match vec_inner.as_ref() {
137 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
138 if returns_ref {
139 let wrap = arc_wrap("x.clone()", n, mutex_types);
140 format!("{expr}.map(|v| v.into_iter().map(|x| {n} {{ inner: {wrap} }}).collect())")
141 } else {
142 let wrap = arc_wrap("x", n, mutex_types);
143 format!("{expr}.map(|v| v.into_iter().map(|x| {n} {{ inner: {wrap} }}).collect())")
144 }
145 }
146 TypeRef::Named(_) => {
147 if returns_ref {
148 format!("{expr}.map(|v| v.into_iter().map(|x| x.clone().into()).collect())")
149 } else {
150 format!("{expr}.map(|v| v.into_iter().map(Into::into).collect())")
151 }
152 }
153 _ => expr.to_string(),
154 },
155 _ => expr.to_string(),
156 },
157 TypeRef::Vec(inner) => match inner.as_ref() {
159 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
160 if returns_ref {
161 let wrap = arc_wrap("v.clone()", n, mutex_types);
162 format!("{expr}.into_iter().map(|v| {n} {{ inner: {wrap} }}).collect()")
163 } else {
164 let wrap = arc_wrap("v", n, mutex_types);
165 format!("{expr}.into_iter().map(|v| {n} {{ inner: {wrap} }}).collect()")
166 }
167 }
168 TypeRef::Named(_) => {
169 if returns_ref {
170 format!("{expr}.into_iter().map(|v| v.clone().into()).collect()")
171 } else {
172 format!("{expr}.into_iter().map(Into::into).collect()")
173 }
174 }
175 TypeRef::Path => {
176 format!("{expr}.into_iter().map(Into::into).collect()")
177 }
178 TypeRef::String | TypeRef::Bytes => {
179 if returns_ref {
180 format!("{expr}.into_iter().map(Into::into).collect()")
181 } else {
182 expr.to_string()
183 }
184 }
185 _ => expr.to_string(),
186 },
187 _ => expr.to_string(),
188 }
189}
190
191pub fn wrap_return(
196 expr: &str,
197 return_type: &TypeRef,
198 type_name: &str,
199 opaque_types: &AHashSet<String>,
200 self_is_opaque: bool,
201 returns_ref: bool,
202 returns_cow: bool,
203) -> String {
204 wrap_return_with_mutex(
205 expr,
206 return_type,
207 type_name,
208 opaque_types,
209 &AHashSet::new(),
210 self_is_opaque,
211 returns_ref,
212 returns_cow,
213 )
214}
215
216pub fn apply_return_newtype_unwrap(expr: &str, return_newtype_wrapper: &Option<String>) -> String {
221 match return_newtype_wrapper {
222 Some(_) => crate::template_env::render(
223 "binding_helpers/return_newtype_unwrap.jinja",
224 minijinja::context! {
225 expr => expr,
226 },
227 )
228 .trim_end_matches('\n')
229 .to_string(),
230 None => expr.to_string(),
231 }
232}
233
234pub fn gen_call_args(params: &[ParamDef], opaque_types: &AHashSet<String>) -> String {
245 params
246 .iter()
247 .enumerate()
248 .map(|(idx, p)| {
249 let promoted = crate::shared::is_promoted_optional(params, idx);
250 let unwrap_suffix = if promoted && p.optional {
255 format!(".expect(\"'{}' is required\")", p.name)
256 } else {
257 String::new()
258 };
259 if let Some(newtype_path) = &p.newtype_wrapper {
262 return if p.optional {
263 format!("{}.map({newtype_path})", p.name)
264 } else if promoted {
265 format!("{newtype_path}({}{})", p.name, unwrap_suffix)
266 } else {
267 format!("{newtype_path}({})", p.name)
268 };
269 }
270 match &p.ty {
271 TypeRef::Named(name) if opaque_types.contains(name.as_str()) => {
272 if p.optional {
274 format!("{}.as_ref().map(|v| &v.inner)", p.name)
275 } else if promoted {
276 format!("{}{}.inner.as_ref()", p.name, unwrap_suffix)
277 } else {
278 format!("&{}.inner", p.name)
279 }
280 }
281 TypeRef::Named(_) => {
282 if p.optional {
283 if p.is_ref {
284 format!("{}.as_ref()", p.name)
287 } else {
288 format!("{}.map(Into::into)", p.name)
289 }
290 } else if promoted {
291 format!("{}{}.into()", p.name, unwrap_suffix)
292 } else {
293 format!("{}.into()", p.name)
294 }
295 }
296 TypeRef::String | TypeRef::Char => {
300 if p.optional {
301 if p.is_ref {
302 format!("{}.as_deref()", p.name)
303 } else {
304 p.name.clone()
305 }
306 } else if promoted {
307 if p.is_ref {
308 format!("&{}{}", p.name, unwrap_suffix)
309 } else {
310 format!("{}{}", p.name, unwrap_suffix)
311 }
312 } else if p.is_ref {
313 format!("&{}", p.name)
314 } else {
315 p.name.clone()
316 }
317 }
318 TypeRef::Path => {
320 if p.optional && p.is_ref {
321 format!("{}.as_deref().map(std::path::Path::new)", p.name)
322 } else if p.optional {
323 format!("{}.map(std::path::PathBuf::from)", p.name)
324 } else if promoted {
325 format!("std::path::PathBuf::from({}{})", p.name, unwrap_suffix)
326 } else if p.is_ref {
327 format!("std::path::Path::new(&{})", p.name)
328 } else {
329 format!("std::path::PathBuf::from({})", p.name)
330 }
331 }
332 TypeRef::Bytes => {
333 if p.optional {
334 if p.is_ref {
335 format!("{}.as_deref()", p.name)
336 } else {
337 p.name.clone()
338 }
339 } else if promoted {
340 if p.is_ref {
343 format!("&{}{}", p.name, unwrap_suffix)
344 } else {
345 format!("{}{}", p.name, unwrap_suffix)
346 }
347 } else {
348 if p.is_ref {
351 format!("&{}", p.name)
352 } else {
353 p.name.clone()
354 }
355 }
356 }
357 TypeRef::Duration => {
359 if p.optional {
360 format!("{}.map(std::time::Duration::from_millis)", p.name)
361 } else if promoted {
362 format!("std::time::Duration::from_millis({}{})", p.name, unwrap_suffix)
363 } else {
364 format!("std::time::Duration::from_millis({})", p.name)
365 }
366 }
367 TypeRef::Json => {
368 if p.optional {
370 format!("{}.as_ref().and_then(|s| serde_json::from_str(s).ok())", p.name)
371 } else if promoted {
372 format!("serde_json::from_str(&{}{}).unwrap_or_default()", p.name, unwrap_suffix)
373 } else {
374 format!("serde_json::from_str(&{}).unwrap_or_default()", p.name)
375 }
376 }
377 TypeRef::Vec(inner) => {
378 if matches!(inner.as_ref(), TypeRef::Named(_)) {
380 if p.optional {
381 if p.is_ref {
382 format!("{}.as_deref()", p.name)
383 } else {
384 p.name.clone()
385 }
386 } else if promoted {
387 if p.is_ref {
388 format!("&{}{}", p.name, unwrap_suffix)
389 } else {
390 format!("{}{}", p.name, unwrap_suffix)
391 }
392 } else if p.is_ref {
393 format!("&{}", p.name)
394 } else {
395 p.name.clone()
396 }
397 } else if promoted {
398 format!("{}{}", p.name, unwrap_suffix)
399 } else if p.is_mut && p.optional {
400 format!("{}.as_deref_mut()", p.name)
401 } else if p.is_mut {
402 format!("&mut {}", p.name)
403 } else if p.is_ref && p.optional {
404 format!("{}.as_deref()", p.name)
405 } else if p.is_ref {
406 format!("&{}", p.name)
407 } else {
408 p.name.clone()
409 }
410 }
411 _ => {
412 if promoted {
413 format!("{}{}", p.name, unwrap_suffix)
414 } else if p.is_mut && p.optional {
415 format!("{}.as_deref_mut()", p.name)
416 } else if p.is_mut {
417 format!("&mut {}", p.name)
418 } else if p.is_ref && p.optional {
419 format!("{}.as_deref()", p.name)
422 } else if p.is_ref {
423 format!("&{}", p.name)
424 } else {
425 p.name.clone()
426 }
427 }
428 }
429 })
430 .collect::<Vec<_>>()
431 .join(", ")
432}
433
434pub fn gen_call_args_cfg(
441 params: &[ParamDef],
442 opaque_types: &AHashSet<String>,
443 cast_uints_to_i32: bool,
444 cast_large_ints_to_f64: bool,
445) -> String {
446 params
447 .iter()
448 .enumerate()
449 .map(|(idx, p)| {
450 let promoted = crate::shared::is_promoted_optional(params, idx);
451 let unwrap_suffix = if promoted && p.optional {
452 format!(".expect(\"'{}' is required\")", p.name)
453 } else {
454 String::new()
455 };
456 if p.newtype_wrapper.is_some() {
458 return gen_call_args(std::slice::from_ref(p), opaque_types);
461 }
462 if let TypeRef::Primitive(prim) = &p.ty {
464 let core_ty = core_prim_str(prim);
465 let needs_cast =
466 (cast_uints_to_i32 && needs_i32_cast(prim)) || (cast_large_ints_to_f64 && needs_f64_cast(prim));
467 if needs_cast {
468 return if p.optional {
469 format!("{}.map(|v| v as {core_ty})", p.name)
470 } else if promoted {
471 format!("({}{}) as {core_ty}", p.name, unwrap_suffix)
472 } else {
473 format!("{} as {core_ty}", p.name)
474 };
475 }
476 }
477 gen_call_args(std::slice::from_ref(p), opaque_types)
479 })
480 .collect::<Vec<_>>()
481 .join(", ")
482}
483
484pub fn gen_call_args_with_let_bindings(params: &[ParamDef], opaque_types: &AHashSet<String>) -> String {
487 params
488 .iter()
489 .enumerate()
490 .map(|(idx, p)| {
491 let promoted = crate::shared::is_promoted_optional(params, idx);
492 let unwrap_suffix = if promoted {
493 format!(".expect(\"'{}' is required\")", p.name)
494 } else {
495 String::new()
496 };
497 if let Some(newtype_path) = &p.newtype_wrapper {
499 return if p.optional {
500 format!("{}.map({newtype_path})", p.name)
501 } else if promoted {
502 format!("{newtype_path}({}{})", p.name, unwrap_suffix)
503 } else {
504 format!("{newtype_path}({})", p.name)
505 };
506 }
507 match &p.ty {
508 TypeRef::Named(name) if opaque_types.contains(name.as_str()) => {
509 if p.optional {
510 format!("{}.as_ref().map(|v| &v.inner)", p.name)
511 } else if promoted {
512 format!("{}{}.inner.as_ref()", p.name, unwrap_suffix)
513 } else {
514 format!("&{}.inner", p.name)
515 }
516 }
517 TypeRef::Named(_) => {
518 if p.optional && p.is_ref {
519 format!("{}_core", p.name)
521 } else if p.is_ref {
522 format!("&{}_core", p.name)
524 } else {
525 format!("{}_core", p.name)
526 }
527 }
528 TypeRef::String | TypeRef::Char => {
529 if p.optional {
530 if p.is_ref {
531 format!("{}.as_deref()", p.name)
532 } else {
533 p.name.clone()
534 }
535 } else if promoted {
536 if p.is_ref {
537 format!("&{}{}", p.name, unwrap_suffix)
538 } else {
539 format!("{}{}", p.name, unwrap_suffix)
540 }
541 } else if p.is_ref {
542 format!("&{}", p.name)
543 } else {
544 p.name.clone()
545 }
546 }
547 TypeRef::Path => {
548 if promoted {
549 format!("std::path::PathBuf::from({}{})", p.name, unwrap_suffix)
550 } else if p.optional && p.is_ref {
551 format!("{}.as_deref().map(std::path::Path::new)", p.name)
552 } else if p.optional {
553 format!("{}.map(std::path::PathBuf::from)", p.name)
554 } else if p.is_ref {
555 format!("std::path::Path::new(&{})", p.name)
556 } else {
557 format!("std::path::PathBuf::from({})", p.name)
558 }
559 }
560 TypeRef::Bytes => {
561 if p.optional {
562 if p.is_ref {
563 format!("{}.as_deref()", p.name)
564 } else {
565 p.name.clone()
566 }
567 } else if promoted {
568 if p.is_ref {
571 format!("&{}{}", p.name, unwrap_suffix)
572 } else {
573 format!("{}{}", p.name, unwrap_suffix)
574 }
575 } else {
576 if p.is_ref {
579 format!("&{}", p.name)
580 } else {
581 p.name.clone()
582 }
583 }
584 }
585 TypeRef::Duration => {
586 if p.optional {
587 format!("{}.map(std::time::Duration::from_millis)", p.name)
588 } else if promoted {
589 format!("std::time::Duration::from_millis({}{})", p.name, unwrap_suffix)
590 } else {
591 format!("std::time::Duration::from_millis({})", p.name)
592 }
593 }
594 TypeRef::Vec(inner) => {
595 if matches!(inner.as_ref(), TypeRef::String) && p.sanitized && p.original_type.is_some() {
598 if p.optional && p.is_ref {
599 format!("{}_core.as_deref()", p.name)
600 } else if p.optional {
601 format!("{}_core", p.name)
602 } else if p.is_ref {
603 format!("&{}_core", p.name)
604 } else {
605 format!("{}_core", p.name)
606 }
607 } else if matches!(inner.as_ref(), TypeRef::Named(_)) {
608 if p.optional && p.is_ref {
610 format!("{}_core.as_deref()", p.name)
612 } else if p.optional {
613 format!("{}_core", p.name)
615 } else if p.is_ref {
616 format!("&{}_core", p.name)
617 } else {
618 format!("{}_core", p.name)
619 }
620 } else if matches!(inner.as_ref(), TypeRef::String | TypeRef::Char) && p.is_ref {
621 if p.optional {
624 format!("{}.as_deref()", p.name)
625 } else {
626 format!("&{}_refs", p.name)
627 }
628 } else if promoted {
629 format!("{}{}", p.name, unwrap_suffix)
630 } else if p.is_ref && p.optional {
631 format!("{}.as_deref()", p.name)
632 } else if p.is_ref {
633 format!("&{}", p.name)
634 } else {
635 p.name.clone()
636 }
637 }
638 _ => {
639 if promoted {
640 format!("{}{}", p.name, unwrap_suffix)
641 } else if p.is_ref && p.optional {
642 format!("{}.as_deref()", p.name)
643 } else if p.is_ref {
644 format!("&{}", p.name)
645 } else {
646 p.name.clone()
647 }
648 }
649 }
650 })
651 .collect::<Vec<_>>()
652 .join(", ")
653}
654
655pub fn gen_named_let_bindings_pub(params: &[ParamDef], opaque_types: &AHashSet<String>, core_import: &str) -> String {
657 gen_named_let_bindings(params, opaque_types, core_import)
658}
659
660pub fn gen_named_let_bindings_no_promote(
663 params: &[ParamDef],
664 opaque_types: &AHashSet<String>,
665 core_import: &str,
666) -> String {
667 gen_named_let_bindings_inner(params, opaque_types, core_import, false)
668}
669
670pub(super) fn gen_named_let_bindings(
671 params: &[ParamDef],
672 opaque_types: &AHashSet<String>,
673 core_import: &str,
674) -> String {
675 gen_named_let_bindings_inner(params, opaque_types, core_import, true)
676}
677
678pub(super) fn gen_named_let_bindings_by_ref(
682 params: &[ParamDef],
683 opaque_types: &AHashSet<String>,
684 core_import: &str,
685) -> String {
686 let mut bindings = String::new();
687 for (idx, p) in params.iter().enumerate() {
688 match &p.ty {
689 TypeRef::Named(name) if !opaque_types.contains(name.as_str()) => {
690 let promoted = crate::shared::is_promoted_optional(params, idx);
691 let core_type_path = format!("{core_import}::{name}");
692 let binding = if p.optional {
693 crate::template_env::render(
694 "binding_helpers/named_let_binding_by_ref_optional.jinja",
695 minijinja::context! {
696 name => &p.name,
697 core_type_path => &core_type_path,
698 },
699 )
700 } else if promoted {
701 crate::template_env::render(
702 "binding_helpers/named_let_binding_by_ref_promoted.jinja",
703 minijinja::context! {
704 name => &p.name,
705 core_type_path => &core_type_path,
706 },
707 )
708 } else {
709 crate::template_env::render(
710 "binding_helpers/named_let_binding_by_ref_simple.jinja",
711 minijinja::context! {
712 name => &p.name,
713 core_type_path => &core_type_path,
714 },
715 )
716 };
717 bindings.push_str(&binding);
718 bindings.push_str("\n ");
719 }
720 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if !opaque_types.contains(n.as_str())) => {
721 let binding = if p.optional {
722 crate::template_env::render(
723 "binding_helpers/vec_named_let_binding_by_ref_optional.jinja",
724 minijinja::context! {
725 name => &p.name,
726 },
727 )
728 } else {
729 let promoted = crate::shared::is_promoted_optional(params, idx);
730 if promoted {
731 crate::template_env::render(
732 "binding_helpers/vec_named_let_binding_by_ref_promoted.jinja",
733 minijinja::context! {
734 name => &p.name,
735 },
736 )
737 } else {
738 crate::template_env::render(
739 "binding_helpers/vec_named_let_binding_by_ref_simple.jinja",
740 minijinja::context! {
741 name => &p.name,
742 },
743 )
744 }
745 };
746 bindings.push_str(&binding);
747 bindings.push_str("\n ");
748 }
749 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::String | TypeRef::Char) && p.is_ref => {
750 let binding = if p.optional {
751 crate::template_env::render(
752 "binding_helpers/vec_string_refs_binding_optional.jinja",
753 minijinja::context! {
754 name => &p.name,
755 },
756 )
757 } else {
758 crate::template_env::render(
759 "binding_helpers/vec_string_refs_binding_simple.jinja",
760 minijinja::context! {
761 name => &p.name,
762 },
763 )
764 };
765 bindings.push_str(&binding);
766 bindings.push_str("\n ");
767 }
768 _ => {}
769 }
770 }
771 bindings
772}
773
774fn gen_named_let_bindings_inner(
775 params: &[ParamDef],
776 opaque_types: &AHashSet<String>,
777 core_import: &str,
778 promote: bool,
779) -> String {
780 let mut bindings = String::new();
781 for (idx, p) in params.iter().enumerate() {
782 match &p.ty {
783 TypeRef::Named(name) if !opaque_types.contains(name.as_str()) => {
784 let promoted = promote && crate::shared::is_promoted_optional(params, idx);
785 let core_type_path = format!("{}::{}", core_import, name);
786 let binding = if p.optional {
787 if p.is_ref {
788 crate::template_env::render(
789 "binding_helpers/named_let_binding_optional_ref.jinja",
790 minijinja::context! {
791 name => &p.name,
792 core_type_path => &core_type_path,
793 },
794 )
795 } else {
796 crate::template_env::render(
797 "binding_helpers/named_let_binding_optional.jinja",
798 minijinja::context! {
799 name => &p.name,
800 core_type_path => &core_type_path,
801 },
802 )
803 }
804 } else if promoted {
805 crate::template_env::render(
806 "binding_helpers/named_let_binding_promoted.jinja",
807 minijinja::context! {
808 name => &p.name,
809 core_type_path => &core_type_path,
810 },
811 )
812 } else {
813 crate::template_env::render(
814 "binding_helpers/named_let_binding_simple.jinja",
815 minijinja::context! {
816 name => &p.name,
817 core_type_path => &core_type_path,
818 },
819 )
820 };
821 bindings.push_str(&binding);
822 bindings.push_str("\n ");
823 }
824 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if !opaque_types.contains(n.as_str())) => {
825 let promoted = promote && crate::shared::is_promoted_optional(params, idx);
826 let binding = if p.optional && p.is_ref {
827 crate::template_env::render(
828 "binding_helpers/vec_named_let_binding_optional.jinja",
829 minijinja::context! {
830 name => &p.name,
831 },
832 )
833 } else if p.optional {
834 crate::template_env::render(
835 "binding_helpers/vec_named_let_binding_optional_no_ref.jinja",
836 minijinja::context! {
837 name => &p.name,
838 },
839 )
840 } else if promoted {
841 crate::template_env::render(
842 "binding_helpers/vec_named_let_binding_promoted.jinja",
843 minijinja::context! {
844 name => &p.name,
845 },
846 )
847 } else {
848 crate::template_env::render(
849 "binding_helpers/vec_named_let_binding_simple.jinja",
850 minijinja::context! {
851 name => &p.name,
852 },
853 )
854 };
855 bindings.push_str(&binding);
856 bindings.push_str("\n ");
857 }
858 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::String | TypeRef::Char) && p.is_ref => {
861 let binding = if p.optional {
862 crate::template_env::render(
863 "binding_helpers/vec_string_refs_binding_optional.jinja",
864 minijinja::context! {
865 name => &p.name,
866 },
867 )
868 } else {
869 crate::template_env::render(
870 "binding_helpers/vec_string_refs_binding_simple.jinja",
871 minijinja::context! {
872 name => &p.name,
873 },
874 )
875 };
876 bindings.push_str(&binding);
877 bindings.push_str("\n ");
878 }
879 TypeRef::Vec(inner)
881 if matches!(inner.as_ref(), TypeRef::String) && p.sanitized && p.original_type.is_some() =>
882 {
883 if p.optional {
884 write!(
885 bindings,
886 "let {n}_core: Option<Vec<_>> = {n}.map(|strs| \
887 strs.into_iter()\n \
888 .filter_map(|s| serde_json::from_str(&s).ok())\n \
889 .collect()\n \
890 );\n ",
891 n = p.name,
892 )
893 .ok();
894 } else {
895 write!(
896 bindings,
897 "let {n}_core: Vec<_> = {n}.into_iter()\n \
898 .filter_map(|s| serde_json::from_str(&s).ok())\n \
899 .collect();\n ",
900 n = p.name,
901 )
902 .ok();
903 }
904 }
905 _ => {}
906 }
907 }
908 bindings
909}
910
911pub fn gen_serde_let_bindings(
918 params: &[ParamDef],
919 opaque_types: &AHashSet<String>,
920 core_import: &str,
921 err_conv: &str,
922 indent: &str,
923) -> String {
924 let mut bindings = String::new();
925 for (idx, p) in params.iter().enumerate() {
926 let promoted = crate::shared::is_promoted_optional(params, idx);
927 match &p.ty {
928 TypeRef::Named(name) if !opaque_types.contains(name.as_str()) => {
929 let core_path = format!("{}::{}", core_import, name);
930 if p.optional {
931 write!(
932 bindings,
933 "let {name}_core: Option<{core_path}> = {name}.map(|v| {{\n\
934 {indent} let json = serde_json::to_string(&v){err_conv}?;\n\
935 {indent} serde_json::from_str(&json){err_conv}\n\
936 {indent}}}).transpose()?;\n{indent}",
937 name = p.name,
938 core_path = core_path,
939 err_conv = err_conv,
940 indent = indent,
941 )
942 .ok();
943 } else if promoted {
944 write!(
948 bindings,
949 "let {name}_core: {core_path} = {name}.map(|v| {{\n\
950 {indent} let json = serde_json::to_string(&v){err_conv}?;\n\
951 {indent} serde_json::from_str::<{core_path}>(&json){err_conv}\n\
952 {indent}}}).transpose()?{indent}.unwrap_or_default();\n{indent}",
953 name = p.name,
954 core_path = core_path,
955 err_conv = err_conv,
956 indent = indent,
957 )
958 .ok();
959 } else {
960 write!(
961 bindings,
962 "let {name}_json = serde_json::to_string(&{name}){err_conv}?;\n\
963 {indent}let {name}_core: {core_path} = serde_json::from_str(&{name}_json){err_conv}?;\n{indent}",
964 name = p.name,
965 core_path = core_path,
966 err_conv = err_conv,
967 indent = indent,
968 )
969 .ok();
970 }
971 }
972 TypeRef::Vec(inner) => {
973 if let TypeRef::Named(name) = inner.as_ref() {
974 if !opaque_types.contains(name.as_str()) {
975 let core_path = format!("{}::{}", core_import, name);
976 if p.optional {
977 write!(
978 bindings,
979 "let {name}_core: Option<Vec<{core_path}>> = {name}.map(|v| {{\n\
980 {indent} let json = serde_json::to_string(&v){err_conv}?;\n\
981 {indent} serde_json::from_str(&json){err_conv}\n\
982 {indent}}}).transpose()?;\n{indent}",
983 name = p.name,
984 core_path = core_path,
985 err_conv = err_conv,
986 indent = indent,
987 )
988 .ok();
989 } else {
990 write!(
991 bindings,
992 "let {name}_json = serde_json::to_string(&{name}){err_conv}?;\n\
993 {indent}let {name}_core: Vec<{core_path}> = serde_json::from_str(&{name}_json){err_conv}?;\n{indent}",
994 name = p.name,
995 core_path = core_path,
996 err_conv = err_conv,
997 indent = indent,
998 )
999 .ok();
1000 }
1001 }
1002 } else if matches!(inner.as_ref(), TypeRef::String) && p.sanitized && p.original_type.is_some() {
1003 if p.optional {
1006 write!(
1007 bindings,
1008 "let {n}_core: Option<Vec<_>> = {n}.map(|strs| {{\n\
1009 {indent} strs.into_iter()\n\
1010 {indent} .map(|s| serde_json::from_str::<_>(&s){err_conv})\n\
1011 {indent} .collect::<Result<Vec<_>, _>>()\n\
1012 {indent}}}).transpose()?;\n{indent}",
1013 n = p.name,
1014 err_conv = err_conv,
1015 indent = indent,
1016 )
1017 .ok();
1018 } else {
1019 write!(
1020 bindings,
1021 "let {n}_core: Vec<_> = {n}.into_iter()\n\
1022 {indent}.map(|s| serde_json::from_str::<_>(&s){err_conv})\n\
1023 {indent}.collect::<Result<Vec<_>, _>>()?;\n{indent}",
1024 n = p.name,
1025 err_conv = err_conv,
1026 indent = indent,
1027 )
1028 .ok();
1029 }
1030 }
1031 }
1032 _ => {}
1033 }
1034 }
1035 bindings
1036}
1037
1038pub fn has_named_params(params: &[ParamDef], opaque_types: &AHashSet<String>) -> bool {
1043 params.iter().any(|p| match &p.ty {
1044 TypeRef::Named(name) if !opaque_types.contains(name.as_str()) => true,
1045 TypeRef::Vec(inner) => {
1046 matches!(inner.as_ref(), TypeRef::Named(name) if !opaque_types.contains(name.as_str()))
1050 || (matches!(inner.as_ref(), TypeRef::String | TypeRef::Char) && p.is_ref)
1051 || (matches!(inner.as_ref(), TypeRef::String) && p.sanitized && p.original_type.is_some())
1052 }
1053 _ => false,
1054 })
1055}
1056
1057pub fn is_simple_non_opaque_param(ty: &TypeRef) -> bool {
1060 match ty {
1061 TypeRef::Primitive(_)
1062 | TypeRef::String
1063 | TypeRef::Char
1064 | TypeRef::Bytes
1065 | TypeRef::Path
1066 | TypeRef::Unit
1067 | TypeRef::Duration => true,
1068 TypeRef::Optional(inner) => is_simple_non_opaque_param(inner),
1069 _ => false,
1070 }
1071}
1072
1073pub fn gen_lossy_binding_to_core_fields(
1086 typ: &TypeDef,
1087 core_import: &str,
1088 option_duration_on_defaults: bool,
1089 opaque_types: &AHashSet<String>,
1090 cast_uints_to_i32: bool,
1091 cast_large_ints_to_f64: bool,
1092 skip_types: &[String],
1093) -> String {
1094 gen_lossy_binding_to_core_fields_inner(
1095 typ,
1096 core_import,
1097 false,
1098 option_duration_on_defaults,
1099 opaque_types,
1100 cast_uints_to_i32,
1101 cast_large_ints_to_f64,
1102 skip_types,
1103 )
1104}
1105
1106pub fn gen_lossy_binding_to_core_fields_mut(
1108 typ: &TypeDef,
1109 core_import: &str,
1110 option_duration_on_defaults: bool,
1111 opaque_types: &AHashSet<String>,
1112 cast_uints_to_i32: bool,
1113 cast_large_ints_to_f64: bool,
1114 skip_types: &[String],
1115) -> String {
1116 gen_lossy_binding_to_core_fields_inner(
1117 typ,
1118 core_import,
1119 true,
1120 option_duration_on_defaults,
1121 opaque_types,
1122 cast_uints_to_i32,
1123 cast_large_ints_to_f64,
1124 skip_types,
1125 )
1126}
1127
1128#[allow(clippy::too_many_arguments)]
1129fn gen_lossy_binding_to_core_fields_inner(
1130 typ: &TypeDef,
1131 core_import: &str,
1132 needs_mut: bool,
1133 option_duration_on_defaults: bool,
1134 opaque_types: &AHashSet<String>,
1135 cast_uints_to_i32: bool,
1136 cast_large_ints_to_f64: bool,
1137 skip_types: &[String],
1138) -> String {
1139 let core_path = crate::conversions::core_type_path(typ, core_import);
1140 let mut_kw = if needs_mut { "mut " } else { "" };
1141 let allow = if typ.has_stripped_cfg_fields {
1146 "#[allow(clippy::needless_update)]\n "
1147 } else {
1148 ""
1149 };
1150 let mut out = format!("{allow}let {mut_kw}core_self = {core_path} {{\n");
1151 for field in &typ.fields {
1152 let name = &field.name;
1153 if field.sanitized && field.core_wrapper != CoreWrapper::Cow {
1154 out.push_str(&crate::template_env::render(
1155 "binding_helpers/struct_field_default.jinja",
1156 minijinja::context! {
1157 name => &field.name,
1158 },
1159 ));
1160 out.push('\n');
1161 continue;
1162 }
1163 let is_opaque_named = match &field.ty {
1168 TypeRef::Named(n) => opaque_types.contains(n.as_str()),
1169 TypeRef::Optional(inner) => {
1170 matches!(inner.as_ref(), TypeRef::Named(n) if opaque_types.contains(n.as_str()))
1171 }
1172 _ => false,
1173 };
1174 if is_opaque_named {
1175 out.push_str(&crate::template_env::render(
1176 "binding_helpers/struct_field_default.jinja",
1177 minijinja::context! {
1178 name => &field.name,
1179 },
1180 ));
1181 out.push('\n');
1182 continue;
1183 }
1184 let is_skip_named = match &field.ty {
1187 TypeRef::Named(n) => skip_types.contains(n),
1188 TypeRef::Optional(inner) => {
1189 matches!(inner.as_ref(), TypeRef::Named(n) if skip_types.contains(n))
1190 }
1191 _ => false,
1192 };
1193 if is_skip_named {
1194 out.push_str(&crate::template_env::render(
1195 "binding_helpers/default_field.jinja",
1196 minijinja::context! {
1197 name => &name,
1198 },
1199 ));
1200 continue;
1201 }
1202 let expr = match &field.ty {
1203 TypeRef::Primitive(p) if cast_uints_to_i32 && needs_i32_cast(p) => {
1204 let core_ty = core_prim_str(p);
1205 if field.optional {
1206 format!("self.{name}.map(|v| v as {core_ty})")
1207 } else {
1208 format!("self.{name} as {core_ty}")
1209 }
1210 }
1211 TypeRef::Primitive(p) if cast_large_ints_to_f64 && needs_f64_cast(p) => {
1212 let core_ty = core_prim_str(p);
1213 if field.optional {
1214 format!("self.{name}.map(|v| v as {core_ty})")
1215 } else {
1216 format!("self.{name} as {core_ty}")
1217 }
1218 }
1219 TypeRef::Primitive(_) => format!("self.{name}"),
1220 TypeRef::Duration => {
1221 if field.optional {
1222 format!("self.{name}.map(std::time::Duration::from_millis)")
1223 } else if option_duration_on_defaults && typ.has_default {
1224 format!("self.{name}.map(std::time::Duration::from_millis).unwrap_or_default()")
1229 } else {
1230 format!("std::time::Duration::from_millis(self.{name})")
1231 }
1232 }
1233 TypeRef::String => {
1234 if field.core_wrapper == CoreWrapper::Cow {
1235 format!("self.{name}.clone().into()")
1236 } else {
1237 format!("self.{name}.clone()")
1238 }
1239 }
1240 TypeRef::Bytes => {
1244 if field.core_wrapper == CoreWrapper::Bytes {
1245 format!("self.{name}.clone().into()")
1246 } else {
1247 format!("self.{name}.clone()")
1248 }
1249 }
1250 TypeRef::Char => {
1251 if field.optional {
1252 format!("self.{name}.as_ref().and_then(|s| s.chars().next())")
1253 } else {
1254 format!("self.{name}.chars().next().unwrap_or('*')")
1255 }
1256 }
1257 TypeRef::Path => {
1258 if field.optional {
1259 format!("self.{name}.clone().map(Into::into)")
1260 } else {
1261 format!("self.{name}.clone().into()")
1262 }
1263 }
1264 TypeRef::Named(_) => {
1265 if field.optional {
1266 format!("self.{name}.clone().map(Into::into)")
1267 } else {
1268 format!("self.{name}.clone().into()")
1269 }
1270 }
1271 TypeRef::Vec(inner) => match inner.as_ref() {
1272 TypeRef::Named(_) => {
1273 if field.optional {
1274 format!("self.{name}.clone().map(|v| v.into_iter().map(Into::into).collect())")
1276 } else {
1277 format!("self.{name}.clone().into_iter().map(Into::into).collect()")
1278 }
1279 }
1280 TypeRef::Primitive(p) if cast_uints_to_i32 && needs_i32_cast(p) => {
1282 let core_ty = core_prim_str(p);
1283 if field.optional {
1284 format!("self.{name}.clone().map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
1285 } else {
1286 format!("self.{name}.clone().into_iter().map(|v| v as {core_ty}).collect()")
1287 }
1288 }
1289 TypeRef::Primitive(p) if cast_large_ints_to_f64 && needs_f64_cast(p) => {
1291 let core_ty = core_prim_str(p);
1292 if field.optional {
1293 format!("self.{name}.clone().map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
1294 } else {
1295 format!("self.{name}.clone().into_iter().map(|v| v as {core_ty}).collect()")
1296 }
1297 }
1298 _ => format!("self.{name}.clone()"),
1299 },
1300 TypeRef::Optional(inner) => {
1301 let base = match inner.as_ref() {
1305 TypeRef::Named(_) => {
1306 format!("self.{name}.clone().map(Into::into)")
1307 }
1308 TypeRef::Duration => {
1309 format!("self.{name}.map(|v| std::time::Duration::from_millis(v as u64))")
1310 }
1311 TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_)) => {
1312 format!("self.{name}.clone().map(|v| v.into_iter().map(Into::into).collect())")
1313 }
1314 TypeRef::Vec(vi) => match vi.as_ref() {
1316 TypeRef::Primitive(p) if cast_uints_to_i32 && needs_i32_cast(p) => {
1317 let core_ty = core_prim_str(p);
1318 format!("self.{name}.clone().map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
1319 }
1320 TypeRef::Primitive(p) if cast_large_ints_to_f64 && needs_f64_cast(p) => {
1322 let core_ty = core_prim_str(p);
1323 format!("self.{name}.clone().map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
1324 }
1325 _ => format!("self.{name}.clone()"),
1326 },
1327 _ => format!("self.{name}.clone()"),
1328 };
1329 if field.optional {
1330 format!("({base}).map(Some)")
1331 } else {
1332 base
1333 }
1334 }
1335 TypeRef::Map(_, v) => match v.as_ref() {
1336 TypeRef::Json => {
1337 if field.optional {
1342 format!(
1343 "self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| \
1344 (k.into(), serde_json::from_str(&v).unwrap_or(serde_json::Value::String(v)))).collect())"
1345 )
1346 } else {
1347 format!(
1348 "self.{name}.clone().into_iter().map(|(k, v)| \
1349 (k.into(), serde_json::from_str(&v).unwrap_or(serde_json::Value::String(v)))).collect()"
1350 )
1351 }
1352 }
1353 TypeRef::Named(_) => {
1356 if field.optional {
1357 format!(
1358 "self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())"
1359 )
1360 } else {
1361 format!("self.{name}.clone().into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
1362 }
1363 }
1364 TypeRef::Primitive(p) if cast_uints_to_i32 && needs_i32_cast(p) => {
1366 let core_ty = core_prim_str(p);
1367 if field.optional {
1368 format!(
1369 "self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| (k.into(), v as {core_ty})).collect())"
1370 )
1371 } else {
1372 format!("self.{name}.clone().into_iter().map(|(k, v)| (k.into(), v as {core_ty})).collect()")
1373 }
1374 }
1375 TypeRef::Primitive(p) if cast_large_ints_to_f64 && needs_f64_cast(p) => {
1377 let core_ty = core_prim_str(p);
1378 if field.optional {
1379 format!(
1380 "self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| (k.into(), v as {core_ty})).collect())"
1381 )
1382 } else {
1383 format!("self.{name}.clone().into_iter().map(|(k, v)| (k.into(), v as {core_ty})).collect()")
1384 }
1385 }
1386 _ => {
1388 if field.optional {
1389 format!("self.{name}.clone().map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
1390 } else {
1391 format!("self.{name}.clone().into_iter().map(|(k, v)| (k.into(), v)).collect()")
1392 }
1393 }
1394 },
1395 TypeRef::Unit => format!("self.{name}.clone()"),
1396 TypeRef::Json => {
1397 if field.optional {
1399 format!("self.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())")
1400 } else {
1401 format!("serde_json::from_str(&self.{name}).unwrap_or_default()")
1402 }
1403 }
1404 };
1405 let expr = if let Some(newtype_path) = &field.newtype_wrapper {
1410 match &field.ty {
1411 TypeRef::Optional(_) => format!("({expr}).map({newtype_path})"),
1412 TypeRef::Vec(_) => format!("({expr}).into_iter().map({newtype_path}).collect::<Vec<_>>()"),
1413 _ if field.optional => format!("({expr}).map({newtype_path})"),
1414 _ => format!("{newtype_path}({expr})"),
1415 }
1416 } else {
1417 expr
1418 };
1419 out.push_str(&crate::template_env::render(
1420 "binding_helpers/struct_field_line.jinja",
1421 minijinja::context! {
1422 name => &field.name,
1423 expr => &expr,
1424 },
1425 ));
1426 out.push('\n');
1427 }
1428 if typ.has_stripped_cfg_fields {
1430 out.push_str(" ..Default::default()\n");
1431 }
1432 out.push_str(" };\n ");
1433 out
1434}
1435
1436#[allow(clippy::too_many_arguments)]
1451pub fn gen_async_body(
1452 core_call: &str,
1453 cfg: &RustBindingConfig,
1454 has_error: bool,
1455 return_wrap: &str,
1456 is_opaque: bool,
1457 inner_clone_line: &str,
1458 is_unit_return: bool,
1459 return_type: Option<&str>,
1460) -> String {
1461 let pattern_body = match cfg.async_pattern {
1462 AsyncPattern::Pyo3FutureIntoPy => {
1463 let result_handling = if has_error {
1464 format!(
1465 "let result = {core_call}.await\n \
1466 .map_err(|e| PyErr::new::<PyRuntimeError, _>(e.to_string()))?;"
1467 )
1468 } else if is_unit_return {
1469 format!("{core_call}.await;")
1470 } else {
1471 format!("let result = {core_call}.await;")
1472 };
1473 let (ok_expr, extra_binding) = if is_unit_return && !has_error {
1474 ("()".to_string(), String::new())
1475 } else if return_wrap.contains(".into()") || return_wrap.contains("::from(") {
1476 let wrapped_var = "wrapped_result";
1480 let binding = if let Some(ret_type) = return_type {
1481 format!("let {wrapped_var}: {ret_type} = {return_wrap};\n ")
1483 } else {
1484 format!("let {wrapped_var} = {return_wrap};\n ")
1485 };
1486 (wrapped_var.to_string(), binding)
1487 } else {
1488 (return_wrap.to_string(), String::new())
1489 };
1490 crate::template_env::render(
1491 "binding_helpers/async_body_pyo3.jinja",
1492 minijinja::context! {
1493 result_handling => result_handling,
1494 extra_binding => extra_binding,
1495 ok_expr => ok_expr,
1496 },
1497 )
1498 }
1499 AsyncPattern::WasmNativeAsync => {
1500 let result_handling = if has_error {
1501 format!(
1502 "let result = {core_call}.await\n \
1503 .map_err(|e| JsValue::from_str(&e.to_string()))?;"
1504 )
1505 } else if is_unit_return {
1506 format!("{core_call}.await;")
1507 } else {
1508 format!("let result = {core_call}.await;")
1509 };
1510 let ok_expr = if is_unit_return && !has_error {
1511 "()"
1512 } else {
1513 return_wrap
1514 };
1515 crate::template_env::render(
1516 "binding_helpers/async_body_wasm.jinja",
1517 minijinja::context! {
1518 result_handling => result_handling,
1519 ok_expr => ok_expr,
1520 },
1521 )
1522 }
1523 AsyncPattern::NapiNativeAsync => {
1524 let result_handling = if has_error {
1525 format!(
1526 "let result = {core_call}.await\n \
1527 .map_err(|e| napi::Error::new(napi::Status::GenericFailure, e.to_string()))?;"
1528 )
1529 } else if is_unit_return {
1530 format!("{core_call}.await;")
1531 } else {
1532 format!("let result = {core_call}.await;")
1533 };
1534 let (needs_ok_wrapper, ok_expr) = if !has_error && !is_unit_return {
1535 (false, return_wrap.to_string())
1537 } else {
1538 let expr = if is_unit_return && !has_error {
1539 "()".to_string()
1540 } else {
1541 return_wrap.to_string()
1542 };
1543 (true, expr)
1544 };
1545 crate::template_env::render(
1546 "binding_helpers/async_body_napi.jinja",
1547 minijinja::context! {
1548 result_handling => result_handling,
1549 needs_ok_wrapper => needs_ok_wrapper,
1550 ok_expr => ok_expr,
1551 return_wrap => return_wrap,
1552 },
1553 )
1554 }
1555 AsyncPattern::TokioBlockOn => {
1556 let rt_new = "tokio::runtime::Runtime::new()\
1557 .map_err(|e| extendr_api::Error::Other(e.to_string()))?";
1558 crate::template_env::render(
1559 "binding_helpers/async_body_tokio.jinja",
1560 minijinja::context! {
1561 has_error => has_error,
1562 is_opaque => is_opaque,
1563 is_unit_return => is_unit_return,
1564 core_call => core_call,
1565 return_wrap => return_wrap,
1566 rt_new => rt_new,
1567 },
1568 )
1569 }
1570 AsyncPattern::None => "todo!(\"async not supported by backend\")".to_string(),
1571 };
1572 if inner_clone_line.is_empty() {
1573 pattern_body
1574 } else {
1575 format!("{inner_clone_line}{pattern_body}")
1576 }
1577}
1578
1579pub fn gen_unimplemented_body(
1586 return_type: &TypeRef,
1587 fn_name: &str,
1588 has_error: bool,
1589 cfg: &RustBindingConfig,
1590 params: &[ParamDef],
1591 opaque_types: &AHashSet<String>,
1592) -> String {
1593 let suppress = if params.is_empty() {
1595 String::new()
1596 } else {
1597 let names: Vec<&str> = params.iter().map(|p| p.name.as_str()).collect();
1598 if names.len() == 1 {
1599 format!("let _ = {};\n ", names[0])
1600 } else {
1601 format!("let _ = ({});\n ", names.join(", "))
1602 }
1603 };
1604 let err_msg = format!("Not implemented: {fn_name}");
1605 let body = if has_error {
1606 match cfg.async_pattern {
1608 AsyncPattern::Pyo3FutureIntoPy => {
1609 format!("Err(pyo3::exceptions::PyNotImplementedError::new_err(\"{err_msg}\"))")
1610 }
1611 AsyncPattern::NapiNativeAsync => {
1612 format!("Err(napi::Error::new(napi::Status::GenericFailure, \"{err_msg}\"))")
1613 }
1614 AsyncPattern::WasmNativeAsync => {
1615 format!("Err(JsValue::from_str(\"{err_msg}\"))")
1616 }
1617 _ => format!("Err(\"{err_msg}\".to_string())"),
1618 }
1619 } else {
1620 match return_type {
1622 TypeRef::Unit => "()".to_string(),
1623 TypeRef::String | TypeRef::Char | TypeRef::Path => format!("String::from(\"[unimplemented: {fn_name}]\")"),
1624 TypeRef::Bytes => "Vec::new()".to_string(),
1625 TypeRef::Primitive(p) => match p {
1626 alef_core::ir::PrimitiveType::Bool => "false".to_string(),
1627 alef_core::ir::PrimitiveType::F32 => "0.0f32".to_string(),
1628 alef_core::ir::PrimitiveType::F64 => "0.0f64".to_string(),
1629 _ => "0".to_string(),
1630 },
1631 TypeRef::Optional(_) => "None".to_string(),
1632 TypeRef::Vec(_) => "Vec::new()".to_string(),
1633 TypeRef::Map(_, _) => "Default::default()".to_string(),
1634 TypeRef::Duration => "0".to_string(),
1635 TypeRef::Named(name) => {
1636 if opaque_types.contains(name.as_str()) {
1640 format!("todo!(\"{err_msg}\")")
1641 } else {
1642 "Default::default()".to_string()
1643 }
1644 }
1645 TypeRef::Json => {
1646 "Default::default()".to_string()
1648 }
1649 }
1650 };
1651 format!("{suppress}{body}")
1652}