1use ahash::AHashSet;
2use alef_core::ir::{CoreWrapper, PrimitiveType, TypeDef, TypeRef};
3
4use super::ConversionConfig;
5use super::binding_to_core::field_conversion_to_core;
6use super::helpers::is_newtype;
7use super::helpers::{binding_prim_str, core_type_path_remapped, needs_f64_cast, needs_i32_cast, needs_i64_cast};
8
9pub fn gen_from_core_to_binding(typ: &TypeDef, core_import: &str, opaque_types: &AHashSet<String>) -> String {
11 gen_from_core_to_binding_cfg(typ, core_import, opaque_types, &ConversionConfig::default())
12}
13
14pub fn gen_from_core_to_binding_cfg(
16 typ: &TypeDef,
17 core_import: &str,
18 opaque_types: &AHashSet<String>,
19 config: &ConversionConfig,
20) -> String {
21 let core_path = core_type_path_remapped(typ, core_import, config.source_crate_remaps);
22 let binding_name = format!("{}{}", config.type_name_prefix, typ.name);
23
24 if is_newtype(typ) {
26 let field = &typ.fields[0];
27 let newtype_inner_expr = match &field.ty {
28 TypeRef::Named(_) => "val.0.into()".to_string(),
29 TypeRef::Path => "val.0.to_string_lossy().to_string()".to_string(),
30 TypeRef::Duration => "val.0.as_millis() as u64".to_string(),
31 _ => "val.0".to_string(),
32 };
33 return crate::template_env::render(
34 "conversions/core_to_binding_impl",
35 minijinja::context! {
36 core_path => core_path,
37 binding_name => binding_name,
38 is_newtype => true,
39 newtype_inner_expr => newtype_inner_expr,
40 fields => vec![] as Vec<String>,
41 },
42 );
43 }
44
45 let optionalized = config.optionalize_defaults && typ.has_default;
46
47 let mut fields = Vec::new();
49 for field in &typ.fields {
50 if field.binding_excluded {
51 continue;
52 }
53 if !config.exclude_types.is_empty()
55 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types)
56 {
57 continue;
58 }
59 if field.cfg.is_some()
64 && !config.never_skip_cfg_field_names.contains(&field.name)
65 && config.strip_cfg_fields_from_binding_struct
66 {
67 continue;
68 }
69 let base_conversion = field_conversion_from_core_cfg(
70 &field.name,
71 &field.ty,
72 field.optional,
73 field.sanitized,
74 opaque_types,
75 config,
76 );
77 let base_conversion = if field.is_boxed && matches!(&field.ty, TypeRef::Named(_)) {
79 if field.optional {
80 let src = format!("{}: val.{}.map(Into::into)", field.name, field.name);
82 let dst = format!("{}: val.{}.map(|v| (*v).into())", field.name, field.name);
83 if base_conversion == src { dst } else { base_conversion }
84 } else {
85 base_conversion.replace(&format!("val.{}", field.name), &format!("(*val.{})", field.name))
87 }
88 } else {
89 base_conversion
90 };
91 let base_conversion = if field.newtype_wrapper.is_some() {
97 match &field.ty {
98 TypeRef::Optional(_) => {
99 base_conversion.replace(
101 &format!("val.{}", field.name),
102 &format!("val.{}.map(|v| v.0)", field.name),
103 )
104 }
105 TypeRef::Vec(_) => {
106 base_conversion.replace(
108 &format!("val.{}", field.name),
109 &format!("val.{}.iter().map(|v| v.0).collect::<Vec<_>>()", field.name),
110 )
111 }
112 _ if field.optional => base_conversion.replace(
115 &format!("val.{}", field.name),
116 &format!("val.{}.map(|v| v.0)", field.name),
117 ),
118 _ => {
119 base_conversion.replace(&format!("val.{}", field.name), &format!("val.{}.0", field.name))
121 }
122 }
123 } else {
124 base_conversion
125 };
126 let is_flattened_optional = field.optional && matches!(field.ty, TypeRef::Optional(_));
132 let base_conversion = if is_flattened_optional {
133 if let TypeRef::Optional(inner) = &field.ty {
134 let inner_conv = field_conversion_from_core_cfg(
136 &field.name,
137 inner.as_ref(),
138 true,
139 field.sanitized,
140 opaque_types,
141 config,
142 );
143 inner_conv.replace(&format!("val.{}", field.name), &format!("val.{}.flatten()", field.name))
145 } else {
146 base_conversion
147 }
148 } else {
149 base_conversion
150 };
151 let needs_some_wrap = !is_flattened_optional
155 && ((optionalized && !field.optional)
156 || (config.option_duration_on_defaults
157 && typ.has_default
158 && !field.optional
159 && matches!(field.ty, TypeRef::Duration)));
160 let conversion = if needs_some_wrap {
161 if let Some(expr) = base_conversion.strip_prefix(&format!("{}: ", field.name)) {
163 format!("{}: Some({})", field.name, expr)
164 } else {
165 base_conversion
166 }
167 } else {
168 base_conversion
169 };
170 let is_opaque_no_wrapper_field = field.core_wrapper == CoreWrapper::None
174 && matches!(&field.ty, TypeRef::Named(n) if config
175 .opaque_types
176 .is_some_and(|opaque| opaque.contains(n.as_str())));
177 let conversion = if is_opaque_no_wrapper_field {
183 if config.trait_bridge_field_is_arc_wrapper(&field.name) {
189 if let TypeRef::Named(name) = &field.ty {
190 let wrapper = format!("{}{}", config.type_name_prefix, name);
191 if field.optional {
192 format!(
193 "{}: val.{}.map(|v| {wrapper} {{ inner: std::sync::Arc::new(v) }})",
194 field.name, field.name
195 )
196 } else {
197 format!(
198 "{}: {wrapper} {{ inner: std::sync::Arc::new(val.{}) }}",
199 field.name, field.name
200 )
201 }
202 } else {
203 format!("{}: Default::default()", field.name)
204 }
205 } else {
206 format!("{}: Default::default()", field.name)
207 }
208 } else if !field.sanitized || field.core_wrapper == alef_core::ir::CoreWrapper::Cow {
209 apply_core_wrapper_from_core(
210 &conversion,
211 &field.name,
212 &field.core_wrapper,
213 &field.vec_inner_core_wrapper,
214 field.optional,
215 )
216 } else {
217 conversion
218 };
219 let binding_field = config.binding_field_name_owned(&typ.name, &field.name);
223 let conversion = if binding_field != field.name {
224 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
225 format!("{binding_field}: {expr}")
226 } else {
227 conversion
228 }
229 } else {
230 conversion
231 };
232 fields.push(conversion);
233 }
234
235 crate::template_env::render(
236 "conversions/core_to_binding_impl",
237 minijinja::context! {
238 core_path => core_path,
239 binding_name => binding_name,
240 is_newtype => false,
241 newtype_inner_expr => "",
242 fields => fields,
243 },
244 )
245}
246
247pub fn field_conversion_from_core(
250 name: &str,
251 ty: &TypeRef,
252 optional: bool,
253 sanitized: bool,
254 opaque_types: &AHashSet<String>,
255) -> String {
256 if sanitized {
260 if let TypeRef::Vec(inner) = ty {
263 if matches!(inner.as_ref(), TypeRef::Primitive(_)) {
264 if optional {
265 return format!(
266 "{name}: val.{name}.map(|t| {{ let arr: Vec<_> = [t.0, t.1].into_iter().map(|v| v as _).collect(); arr }})"
267 );
268 }
269 return format!("{name}: vec![val.{name}.0 as _, val.{name}.1 as _]");
270 }
271 }
272 if let TypeRef::Optional(opt_inner) = ty {
274 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
275 if matches!(vec_inner.as_ref(), TypeRef::Primitive(_)) {
276 return format!("{name}: val.{name}.map(|t| vec![t.0 as _, t.1 as _])");
277 }
278 }
279 }
280 if let TypeRef::Map(k, v) = ty {
282 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
283 if optional {
284 return format!(
285 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
286 );
287 }
288 return format!(
289 "{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()"
290 );
291 }
292 }
293 if let TypeRef::Vec(inner) = ty {
296 if matches!(inner.as_ref(), TypeRef::String) {
297 if optional {
298 return format!(
299 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
300 );
301 }
302 return format!("{name}: val.{name}.iter().map(|i| format!(\"{{:?}}\", i)).collect()");
303 }
304 }
305 if let TypeRef::Optional(opt_inner) = ty {
307 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
308 if matches!(vec_inner.as_ref(), TypeRef::String) {
309 return format!(
310 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
311 );
312 }
313 }
314 }
315 if matches!(ty, TypeRef::String) {
320 if optional {
321 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
322 }
323 return format!("{name}: format!(\"{{:?}}\", val.{name})");
324 }
325 if optional {
328 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
329 }
330 return format!("{name}: format!(\"{{:?}}\", val.{name})");
331 }
332 match ty {
333 TypeRef::Duration => {
335 if optional {
336 return format!("{name}: val.{name}.map(|d| d.as_millis() as u64)");
337 }
338 format!("{name}: val.{name}.as_millis() as u64")
339 }
340 TypeRef::Path => {
342 if optional {
343 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
344 } else {
345 format!("{name}: val.{name}.to_string_lossy().to_string()")
346 }
347 }
348 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
349 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
350 }
351 TypeRef::Char => {
353 if optional {
354 format!("{name}: val.{name}.map(|c| c.to_string())")
355 } else {
356 format!("{name}: val.{name}.to_string()")
357 }
358 }
359 TypeRef::Bytes => {
363 if optional {
364 format!("{name}: val.{name}.map(|v| v.to_vec().into())")
365 } else {
366 format!("{name}: val.{name}.to_vec().into()")
367 }
368 }
369 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
371 if optional {
372 format!("{name}: val.{name}.map(|v| {n} {{ inner: Arc::new(v) }})")
373 } else {
374 format!("{name}: {n} {{ inner: Arc::new(val.{name}) }}")
375 }
376 }
377 TypeRef::Json => {
379 if optional {
380 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
381 } else {
382 format!("{name}: val.{name}.to_string()")
383 }
384 }
385 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
386 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
387 }
388 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
389 if optional {
390 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.to_string()).collect())")
391 } else {
392 format!("{name}: val.{name}.iter().map(ToString::to_string).collect()")
393 }
394 }
395 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Optional(oi) if matches!(oi.as_ref(), TypeRef::Json)) => {
397 if optional {
398 format!(
399 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.as_ref().map(ToString::to_string)).collect())"
400 )
401 } else {
402 format!("{name}: val.{name}.iter().map(|i| i.as_ref().map(ToString::to_string)).collect()")
403 }
404 }
405 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Json) => {
410 if optional {
411 format!(
412 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
413 )
414 } else {
415 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()")
416 }
417 }
418 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
420 if optional {
421 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect())")
422 } else {
423 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v)).collect()")
424 }
425 }
426 TypeRef::Map(k, v) if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) => {
430 if optional {
431 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())")
432 } else {
433 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
434 }
435 }
436 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Bytes) => {
439 if optional {
440 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect())")
441 } else {
442 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect()")
443 }
444 }
445 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_)) => {
447 if optional {
448 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
449 } else {
450 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.into())).collect()")
451 }
452 }
453 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_))) =>
455 {
456 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
457 }
458 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
460 if optional {
461 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
462 } else {
463 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
464 }
465 }
466 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_))) =>
468 {
469 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
470 }
471 _ => field_conversion_to_core(name, ty, optional),
473 }
474}
475
476pub fn field_conversion_from_core_cfg(
478 name: &str,
479 ty: &TypeRef,
480 optional: bool,
481 sanitized: bool,
482 opaque_types: &AHashSet<String>,
483 config: &ConversionConfig,
484) -> String {
485 if sanitized {
490 if config.map_uses_jsvalue {
491 if let TypeRef::Map(k, v) = ty {
494 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
495 if optional {
496 return format!(
497 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
498 );
499 }
500 return format!(
501 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
502 );
503 }
504 }
505 if let TypeRef::Vec(inner) = ty {
507 if matches!(inner.as_ref(), TypeRef::Json) {
508 if optional {
509 return format!(
510 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
511 );
512 }
513 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
514 }
515 }
516 }
517 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
518 }
519
520 if config.map_uses_jsvalue {
525 if let Some(tagged_names) = config.tagged_data_enum_names {
526 let bare_named = matches!(ty, TypeRef::Named(n) if tagged_names.contains(n));
527 let optional_named = matches!(ty, TypeRef::Optional(inner)
528 if matches!(inner.as_ref(), TypeRef::Named(n) if tagged_names.contains(n)));
529 let vec_named = matches!(ty, TypeRef::Vec(inner)
530 if matches!(inner.as_ref(), TypeRef::Named(n) if tagged_names.contains(n)));
531 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
532 if matches!(outer.as_ref(), TypeRef::Vec(inner)
533 if matches!(inner.as_ref(), TypeRef::Named(n) if tagged_names.contains(n))));
534 if bare_named {
535 if optional {
537 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
538 }
539 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
540 }
541 if optional_named {
542 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
544 }
545 if vec_named {
546 if optional {
547 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
548 }
549 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
550 }
551 if optional_vec_named {
552 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
553 }
554 }
555 }
556
557 if let Some(untagged_names) = config.untagged_data_enum_names {
560 let direct_named = matches!(ty, TypeRef::Named(n) if untagged_names.contains(n));
561 let optional_named = matches!(ty, TypeRef::Optional(inner)
562 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
563 let vec_named = matches!(ty, TypeRef::Vec(inner)
564 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
565 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
566 if matches!(outer.as_ref(), TypeRef::Vec(inner)
567 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n))));
568 if direct_named {
569 if optional {
570 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
571 }
572 return format!("{name}: serde_json::to_value(&val.{name}).unwrap_or(serde_json::Value::Null)");
573 }
574 if optional_named {
575 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
576 }
577 if vec_named {
578 if optional {
579 return format!(
580 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
581 );
582 }
583 return format!("{name}: val.{name}.iter().filter_map(|x| serde_json::to_value(x).ok()).collect()");
584 }
585 if optional_vec_named {
586 return format!(
587 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
588 );
589 }
590 }
591
592 if config.vec_named_to_string {
596 if let TypeRef::Vec(inner) = ty {
597 if matches!(inner.as_ref(), TypeRef::Named(_)) {
598 if optional {
599 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok())");
600 }
601 return format!("{name}: serde_json::to_string(&val.{name}).unwrap_or_default()");
602 }
603 }
604 }
605
606 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
609 if optional {
610 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
611 }
612 return format!("{name}: format!(\"{{:?}}\", val.{name})");
613 }
614 if config.map_as_string {
615 if let TypeRef::Optional(inner) = ty {
616 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
617 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
618 }
619 }
620 }
621
622 if config.map_uses_jsvalue {
626 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
627 let is_map = matches!(ty, TypeRef::Map(_, _));
628 if is_map {
629 if optional {
630 return format!(
631 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
632 );
633 }
634 return format!(
635 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
636 );
637 }
638 if is_nested_vec {
639 if optional {
640 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
641 }
642 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
643 }
644 if let TypeRef::Optional(inner) = ty {
645 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
646 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
647 if is_inner_map {
648 return format!(
649 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
650 );
651 }
652 if is_inner_nested {
653 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
654 }
655 }
656 }
657
658 let prefix = config.type_name_prefix;
659 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
660
661 match ty {
662 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
664 let cast_to = binding_prim_str(p);
665 if optional {
666 format!("{name}: val.{name}.map(|v| v as {cast_to})")
667 } else {
668 format!("{name}: val.{name} as {cast_to}")
669 }
670 }
671 TypeRef::Optional(inner)
673 if config.cast_large_ints_to_i64
674 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
675 {
676 if let TypeRef::Primitive(p) = inner.as_ref() {
677 let cast_to = binding_prim_str(p);
678 format!("{name}: val.{name}.map(|v| v as {cast_to})")
679 } else {
680 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
681 }
682 }
683 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
685 if optional {
686 format!("{name}: val.{name}.map(|v| v as i32)")
687 } else {
688 format!("{name}: val.{name} as i32")
689 }
690 }
691 TypeRef::Optional(inner)
693 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
694 {
695 format!("{name}: val.{name}.map(|v| v as i32)")
696 }
697 TypeRef::Vec(inner)
699 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
700 {
701 if let TypeRef::Primitive(_p) = inner.as_ref() {
702 if optional {
703 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as i32).collect())")
704 } else {
705 format!("{name}: val.{name}.iter().map(|&v| v as i32).collect()")
706 }
707 } else {
708 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
709 }
710 }
711 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
713 if optional {
714 format!("{name}: val.{name}.map(|v| v as f64)")
715 } else {
716 format!("{name}: val.{name} as f64")
717 }
718 }
719 TypeRef::Optional(inner)
721 if config.cast_large_ints_to_f64
722 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
723 {
724 format!("{name}: val.{name}.map(|v| v as f64)")
725 }
726 TypeRef::Vec(inner)
728 if config.cast_large_ints_to_f64
729 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
730 {
731 if optional {
732 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
733 } else {
734 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
735 }
736 }
737 TypeRef::Optional(inner)
739 if config.cast_large_ints_to_f64
740 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
741 {
742 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
743 }
744 TypeRef::Vec(outer)
746 if config.cast_large_ints_to_f64
747 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
748 {
749 if optional {
750 format!(
751 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
752 )
753 } else {
754 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
755 }
756 }
757 TypeRef::Optional(inner)
759 if config.cast_large_ints_to_f64
760 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)))) =>
761 {
762 format!(
763 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
764 )
765 }
766 TypeRef::Map(_k, v)
768 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
769 {
770 if optional {
771 format!("{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as f64)).collect())")
772 } else {
773 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as f64)).collect()")
774 }
775 }
776 TypeRef::Duration if config.cast_large_ints_to_f64 => {
778 if optional {
779 format!("{name}: val.{name}.map(|d| d.as_millis() as f64)")
780 } else {
781 format!("{name}: val.{name}.as_millis() as f64")
782 }
783 }
784 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
786 if optional {
787 format!("{name}: val.{name}.map(|v| v as f64)")
788 } else {
789 format!("{name}: val.{name} as f64")
790 }
791 }
792 TypeRef::Duration if config.cast_large_ints_to_i64 => {
794 if optional {
795 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
796 } else {
797 format!("{name}: val.{name}.as_millis() as u64 as i64")
798 }
799 }
800 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
802 let prefixed = format!("{prefix}{n}");
803 if optional {
804 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
805 } else {
806 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
807 }
808 }
809 TypeRef::Named(n) if is_enum_string(n) => {
811 if optional {
814 format!(
815 "{name}: val.{name}.as_ref().map(|v| serde_json::to_value(v).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default())"
816 )
817 } else {
818 format!(
819 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
820 )
821 }
822 }
823 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
825 if optional {
826 format!(
827 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|x| serde_json::to_value(x).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()).collect())"
828 )
829 } else {
830 format!(
831 "{name}: val.{name}.iter().map(|v| serde_json::to_value(v).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()).collect()"
832 )
833 }
834 }
835 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
837 {
838 format!(
839 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|x| serde_json::to_value(x).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()).collect())"
840 )
841 }
842 TypeRef::Vec(inner)
844 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
845 {
846 if optional {
847 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
848 } else {
849 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
850 }
851 }
852 TypeRef::Optional(inner)
854 if config.cast_f32_to_f64
855 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
856 {
857 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
858 }
859 TypeRef::Optional(inner)
861 if config.cast_large_ints_to_i64
862 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
863 {
864 if let TypeRef::Vec(vi) = inner.as_ref() {
865 if let TypeRef::Primitive(p) = vi.as_ref() {
866 let cast_to = binding_prim_str(p);
867 if sanitized {
868 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
870 } else {
871 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
872 }
873 } else {
874 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
875 }
876 } else {
877 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
878 }
879 }
880 TypeRef::Vec(outer)
882 if config.cast_f32_to_f64
883 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
884 {
885 if optional {
886 format!(
887 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
888 )
889 } else {
890 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
891 }
892 }
893 TypeRef::Optional(inner)
895 if config.cast_f32_to_f64
896 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
897 {
898 format!(
899 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
900 )
901 }
902 TypeRef::Optional(inner)
904 if config.cast_large_ints_to_i64
905 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
906 {
907 if let TypeRef::Primitive(p) = inner.as_ref() {
908 let cast_to = binding_prim_str(p);
909 format!("{name}: val.{name}.map(|v| v as {cast_to})")
910 } else {
911 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
912 }
913 }
914 TypeRef::Map(_k, v)
916 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
917 {
918 if let TypeRef::Primitive(p) = v.as_ref() {
919 let cast_to = binding_prim_str(p);
920 if optional {
921 format!(
922 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
923 )
924 } else {
925 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
926 }
927 } else {
928 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
929 }
930 }
931 TypeRef::Vec(inner)
933 if config.cast_large_ints_to_i64
934 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
935 {
936 if let TypeRef::Primitive(p) = inner.as_ref() {
937 let cast_to = binding_prim_str(p);
938 if sanitized {
939 if optional {
941 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
942 } else {
943 format!("{name}: {{ let (a, b) = val.{name}; vec![a as {cast_to}, b as {cast_to}] }}")
944 }
945 } else if optional {
946 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
947 } else {
948 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
949 }
950 } else {
951 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
952 }
953 }
954 TypeRef::Vec(outer)
956 if config.cast_large_ints_to_i64
957 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
958 {
959 if let TypeRef::Vec(inner) = outer.as_ref() {
960 if let TypeRef::Primitive(p) = inner.as_ref() {
961 let cast_to = binding_prim_str(p);
962 if optional {
963 format!(
964 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
965 )
966 } else {
967 format!(
968 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
969 )
970 }
971 } else {
972 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
973 }
974 } else {
975 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
976 }
977 }
978 TypeRef::Json if config.json_to_string => {
980 if optional {
981 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
982 } else {
983 format!("{name}: val.{name}.to_string()")
984 }
985 }
986 TypeRef::Json if config.json_as_value => {
988 format!("{name}: val.{name}")
989 }
990 TypeRef::Optional(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
991 format!("{name}: val.{name}")
992 }
993 TypeRef::Vec(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
994 if optional {
995 format!("{name}: Some(val.{name})")
996 } else {
997 format!("{name}: val.{name}")
998 }
999 }
1000 TypeRef::Map(_k, v) if config.json_as_value && matches!(v.as_ref(), TypeRef::Json) => {
1001 if optional {
1002 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
1003 } else {
1004 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v)).collect()")
1005 }
1006 }
1007 TypeRef::Json if config.map_uses_jsvalue => {
1009 if optional {
1010 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
1011 } else {
1012 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
1013 }
1014 }
1015 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
1017 if optional {
1018 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
1019 } else {
1020 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
1021 }
1022 }
1023 TypeRef::Optional(inner)
1025 if config.map_uses_jsvalue
1026 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
1027 {
1028 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
1029 }
1030 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
1032 }
1033}
1034
1035fn apply_core_wrapper_from_core(
1038 conversion: &str,
1039 name: &str,
1040 core_wrapper: &CoreWrapper,
1041 vec_inner_core_wrapper: &CoreWrapper,
1042 optional: bool,
1043) -> String {
1044 if *vec_inner_core_wrapper == CoreWrapper::Arc {
1046 return conversion
1047 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
1048 .replace(
1049 "map(|v| v.into_iter().map(Into::into)",
1050 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
1051 );
1052 }
1053
1054 match core_wrapper {
1055 CoreWrapper::None => conversion.to_string(),
1056 CoreWrapper::Cow => {
1057 let prefix = format!("{name}: ");
1064 let already_some_wrapped = conversion
1065 .strip_prefix(&prefix)
1066 .is_some_and(|expr| expr.starts_with("Some("));
1067 if optional {
1068 format!("{name}: val.{name}.as_ref().map(|v| v.to_string())")
1069 } else if already_some_wrapped {
1070 format!("{name}: Some(val.{name}.to_string())")
1071 } else {
1072 format!("{name}: val.{name}.to_string()")
1073 }
1074 }
1075 CoreWrapper::Arc => {
1076 if conversion.contains("{ inner: Arc::new(") {
1085 return conversion.replace("{ inner: Arc::new(v) }", "{ inner: v }").replace(
1086 &format!("{{ inner: Arc::new(val.{name}) }}"),
1087 &format!("{{ inner: val.{name} }}"),
1088 );
1089 }
1090 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1091 if optional {
1092 let simple_passthrough = format!("val.{name}");
1101 if expr == simple_passthrough {
1102 format!("{name}: {expr}.map(|v| (*v).clone().into())")
1103 } else {
1104 format!("{name}: {expr}")
1105 }
1106 } else {
1107 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
1108 format!("{name}: {unwrapped}")
1109 }
1110 } else {
1111 conversion.to_string()
1112 }
1113 }
1114 CoreWrapper::Bytes => {
1115 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1120 let already_converted_non_opt = expr == format!("val.{name}.to_vec().into()");
1121 let already_converted_opt = expr == format!("val.{name}.map(|v| v.to_vec().into())");
1122 if already_converted_non_opt || already_converted_opt {
1123 conversion.to_string()
1124 } else if optional {
1125 format!("{name}: {expr}.map(|v| v.to_vec().into())")
1126 } else if expr == format!("val.{name}") {
1127 format!("{name}: val.{name}.to_vec().into()")
1128 } else {
1129 conversion.to_string()
1130 }
1131 } else {
1132 conversion.to_string()
1133 }
1134 }
1135 CoreWrapper::ArcMutex => {
1136 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1138 if optional {
1139 format!("{name}: {expr}.map(|v| v.lock().unwrap().clone().into())")
1140 } else if expr == format!("val.{name}") {
1141 format!("{name}: val.{name}.lock().unwrap().clone().into()")
1142 } else {
1143 conversion.to_string()
1144 }
1145 } else {
1146 conversion.to_string()
1147 }
1148 }
1149 }
1150}