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 TypeRef::Vec(_) => {
476 if optional {
477 format!("{name}: val.{name}.map(|v| v.into_iter().collect())")
478 } else {
479 format!("{name}: val.{name}.into_iter().collect()")
480 }
481 }
482 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)) => {
484 format!("{name}: val.{name}.map(|v| v.into_iter().collect())")
485 }
486 _ => field_conversion_to_core(name, ty, optional),
488 }
489}
490
491pub fn field_conversion_from_core_cfg(
493 name: &str,
494 ty: &TypeRef,
495 optional: bool,
496 sanitized: bool,
497 opaque_types: &AHashSet<String>,
498 config: &ConversionConfig,
499) -> String {
500 if sanitized {
505 if config.map_uses_jsvalue {
506 if let TypeRef::Map(k, v) = ty {
509 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
510 if optional {
511 return format!(
512 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
513 );
514 }
515 return format!(
516 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
517 );
518 }
519 }
520 if let TypeRef::Vec(inner) = ty {
522 if matches!(inner.as_ref(), TypeRef::Json) {
523 if optional {
524 return format!(
525 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
526 );
527 }
528 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
529 }
530 }
531 }
532 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
533 }
534
535 if config.map_uses_jsvalue {
540 if let Some(tagged_names) = config.tagged_data_enum_names {
541 let bare_named = matches!(ty, TypeRef::Named(n) if tagged_names.contains(n));
542 let optional_named = matches!(ty, TypeRef::Optional(inner)
543 if matches!(inner.as_ref(), TypeRef::Named(n) if tagged_names.contains(n)));
544 let vec_named = matches!(ty, TypeRef::Vec(inner)
545 if matches!(inner.as_ref(), TypeRef::Named(n) if tagged_names.contains(n)));
546 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
547 if matches!(outer.as_ref(), TypeRef::Vec(inner)
548 if matches!(inner.as_ref(), TypeRef::Named(n) if tagged_names.contains(n))));
549 if bare_named {
550 if optional {
552 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
553 }
554 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
555 }
556 if optional_named {
557 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
559 }
560 if vec_named {
561 if optional {
562 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
563 }
564 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
565 }
566 if optional_vec_named {
567 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
568 }
569 }
570 }
571
572 if let Some(untagged_names) = config.untagged_data_enum_names {
575 let direct_named = matches!(ty, TypeRef::Named(n) if untagged_names.contains(n));
576 let optional_named = matches!(ty, TypeRef::Optional(inner)
577 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
578 let vec_named = matches!(ty, TypeRef::Vec(inner)
579 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
580 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
581 if matches!(outer.as_ref(), TypeRef::Vec(inner)
582 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n))));
583 if direct_named {
584 if optional {
585 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
586 }
587 return format!("{name}: serde_json::to_value(&val.{name}).unwrap_or(serde_json::Value::Null)");
588 }
589 if optional_named {
590 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
591 }
592 if vec_named {
593 if optional {
594 return format!(
595 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
596 );
597 }
598 return format!("{name}: val.{name}.iter().filter_map(|x| serde_json::to_value(x).ok()).collect()");
599 }
600 if optional_vec_named {
601 return format!(
602 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
603 );
604 }
605 }
606
607 if config.vec_named_to_string {
611 if let TypeRef::Vec(inner) = ty {
612 if matches!(inner.as_ref(), TypeRef::Named(_)) {
613 if optional {
614 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok())");
615 }
616 return format!("{name}: serde_json::to_string(&val.{name}).unwrap_or_default()");
617 }
618 }
619 }
620
621 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
624 if optional {
625 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
626 }
627 return format!("{name}: format!(\"{{:?}}\", val.{name})");
628 }
629 if config.map_as_string {
630 if let TypeRef::Optional(inner) = ty {
631 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
632 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
633 }
634 }
635 }
636
637 if config.map_uses_jsvalue {
641 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
642 let is_map = matches!(ty, TypeRef::Map(_, _));
643 if is_map {
644 if optional {
645 return format!(
646 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
647 );
648 }
649 return format!(
650 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
651 );
652 }
653 if is_nested_vec {
654 if optional {
655 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
656 }
657 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
658 }
659 if let TypeRef::Optional(inner) = ty {
660 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
661 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
662 if is_inner_map {
663 return format!(
664 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
665 );
666 }
667 if is_inner_nested {
668 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
669 }
670 }
671 }
672
673 let prefix = config.type_name_prefix;
674 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
675
676 match ty {
677 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
679 let cast_to = binding_prim_str(p);
680 if optional {
681 format!("{name}: val.{name}.map(|v| v as {cast_to})")
682 } else {
683 format!("{name}: val.{name} as {cast_to}")
684 }
685 }
686 TypeRef::Optional(inner)
688 if config.cast_large_ints_to_i64
689 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
690 {
691 if let TypeRef::Primitive(p) = inner.as_ref() {
692 let cast_to = binding_prim_str(p);
693 format!("{name}: val.{name}.map(|v| v as {cast_to})")
694 } else {
695 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
696 }
697 }
698 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
700 if optional {
701 format!("{name}: val.{name}.map(|v| v as i32)")
702 } else {
703 format!("{name}: val.{name} as i32")
704 }
705 }
706 TypeRef::Optional(inner)
708 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
709 {
710 format!("{name}: val.{name}.map(|v| v as i32)")
711 }
712 TypeRef::Vec(inner)
714 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
715 {
716 if let TypeRef::Primitive(_p) = inner.as_ref() {
717 if optional {
718 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as i32).collect())")
719 } else {
720 format!("{name}: val.{name}.iter().map(|&v| v as i32).collect()")
721 }
722 } else {
723 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
724 }
725 }
726 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
728 if optional {
729 format!("{name}: val.{name}.map(|v| v as f64)")
730 } else {
731 format!("{name}: val.{name} as f64")
732 }
733 }
734 TypeRef::Optional(inner)
736 if config.cast_large_ints_to_f64
737 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
738 {
739 format!("{name}: val.{name}.map(|v| v as f64)")
740 }
741 TypeRef::Vec(inner)
743 if config.cast_large_ints_to_f64
744 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
745 {
746 if optional {
747 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
748 } else {
749 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
750 }
751 }
752 TypeRef::Optional(inner)
754 if config.cast_large_ints_to_f64
755 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
756 {
757 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
758 }
759 TypeRef::Vec(outer)
761 if config.cast_large_ints_to_f64
762 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
763 {
764 if optional {
765 format!(
766 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
767 )
768 } else {
769 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
770 }
771 }
772 TypeRef::Optional(inner)
774 if config.cast_large_ints_to_f64
775 && 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)))) =>
776 {
777 format!(
778 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
779 )
780 }
781 TypeRef::Map(_k, v)
783 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
784 {
785 if optional {
786 format!("{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as f64)).collect())")
787 } else {
788 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as f64)).collect()")
789 }
790 }
791 TypeRef::Duration if config.cast_large_ints_to_f64 => {
793 if optional {
794 format!("{name}: val.{name}.map(|d| d.as_millis() as f64)")
795 } else {
796 format!("{name}: val.{name}.as_millis() as f64")
797 }
798 }
799 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
801 if optional {
802 format!("{name}: val.{name}.map(|v| v as f64)")
803 } else {
804 format!("{name}: val.{name} as f64")
805 }
806 }
807 TypeRef::Duration if config.cast_large_ints_to_i64 => {
809 if optional {
810 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
811 } else {
812 format!("{name}: val.{name}.as_millis() as u64 as i64")
813 }
814 }
815 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
817 let prefixed = format!("{prefix}{n}");
818 if optional {
819 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
820 } else {
821 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
822 }
823 }
824 TypeRef::Named(n) if is_enum_string(n) => {
826 if optional {
829 format!(
830 "{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())"
831 )
832 } else {
833 format!(
834 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
835 )
836 }
837 }
838 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
840 if optional {
841 format!(
842 "{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())"
843 )
844 } else {
845 format!(
846 "{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()"
847 )
848 }
849 }
850 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
852 {
853 format!(
854 "{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())"
855 )
856 }
857 TypeRef::Vec(inner)
859 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
860 {
861 if optional {
862 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
863 } else {
864 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
865 }
866 }
867 TypeRef::Optional(inner)
869 if config.cast_f32_to_f64
870 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
871 {
872 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
873 }
874 TypeRef::Optional(inner)
876 if config.cast_large_ints_to_i64
877 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
878 {
879 if let TypeRef::Vec(vi) = inner.as_ref() {
880 if let TypeRef::Primitive(p) = vi.as_ref() {
881 let cast_to = binding_prim_str(p);
882 if sanitized {
883 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
885 } else {
886 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
887 }
888 } else {
889 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
890 }
891 } else {
892 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
893 }
894 }
895 TypeRef::Vec(outer)
897 if config.cast_f32_to_f64
898 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
899 {
900 if optional {
901 format!(
902 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
903 )
904 } else {
905 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
906 }
907 }
908 TypeRef::Optional(inner)
910 if config.cast_f32_to_f64
911 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
912 {
913 format!(
914 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
915 )
916 }
917 TypeRef::Optional(inner)
919 if config.cast_large_ints_to_i64
920 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
921 {
922 if let TypeRef::Primitive(p) = inner.as_ref() {
923 let cast_to = binding_prim_str(p);
924 format!("{name}: val.{name}.map(|v| v as {cast_to})")
925 } else {
926 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
927 }
928 }
929 TypeRef::Map(_k, v)
931 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
932 {
933 if let TypeRef::Primitive(p) = v.as_ref() {
934 let cast_to = binding_prim_str(p);
935 if optional {
936 format!(
937 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
938 )
939 } else {
940 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
941 }
942 } else {
943 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
944 }
945 }
946 TypeRef::Vec(inner)
948 if config.cast_large_ints_to_i64
949 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
950 {
951 if let TypeRef::Primitive(p) = inner.as_ref() {
952 let cast_to = binding_prim_str(p);
953 if sanitized {
954 if optional {
956 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
957 } else {
958 format!("{name}: {{ let (a, b) = val.{name}; vec![a as {cast_to}, b as {cast_to}] }}")
959 }
960 } else if optional {
961 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
962 } else {
963 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
964 }
965 } else {
966 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
967 }
968 }
969 TypeRef::Vec(outer)
971 if config.cast_large_ints_to_i64
972 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
973 {
974 if let TypeRef::Vec(inner) = outer.as_ref() {
975 if let TypeRef::Primitive(p) = inner.as_ref() {
976 let cast_to = binding_prim_str(p);
977 if optional {
978 format!(
979 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
980 )
981 } else {
982 format!(
983 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
984 )
985 }
986 } else {
987 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
988 }
989 } else {
990 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
991 }
992 }
993 TypeRef::Json if config.json_to_string => {
995 if optional {
996 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
997 } else {
998 format!("{name}: val.{name}.to_string()")
999 }
1000 }
1001 TypeRef::Json if config.json_as_value => {
1003 format!("{name}: val.{name}")
1004 }
1005 TypeRef::Optional(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
1006 format!("{name}: val.{name}")
1007 }
1008 TypeRef::Vec(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
1009 if optional {
1010 format!("{name}: Some(val.{name})")
1011 } else {
1012 format!("{name}: val.{name}")
1013 }
1014 }
1015 TypeRef::Map(_k, v) if config.json_as_value && matches!(v.as_ref(), TypeRef::Json) => {
1016 if optional {
1017 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
1018 } else {
1019 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v)).collect()")
1020 }
1021 }
1022 TypeRef::Json if config.map_uses_jsvalue => {
1024 if optional {
1025 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
1026 } else {
1027 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
1028 }
1029 }
1030 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
1032 if optional {
1033 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
1034 } else {
1035 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
1036 }
1037 }
1038 TypeRef::Optional(inner)
1040 if config.map_uses_jsvalue
1041 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
1042 {
1043 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
1044 }
1045 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
1047 }
1048}
1049
1050fn apply_core_wrapper_from_core(
1053 conversion: &str,
1054 name: &str,
1055 core_wrapper: &CoreWrapper,
1056 vec_inner_core_wrapper: &CoreWrapper,
1057 optional: bool,
1058) -> String {
1059 if *vec_inner_core_wrapper == CoreWrapper::Arc {
1061 return conversion
1062 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
1063 .replace(
1064 "map(|v| v.into_iter().map(Into::into)",
1065 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
1066 );
1067 }
1068
1069 match core_wrapper {
1070 CoreWrapper::None => conversion.to_string(),
1071 CoreWrapper::Cow => {
1072 let prefix = format!("{name}: ");
1079 let already_some_wrapped = conversion
1080 .strip_prefix(&prefix)
1081 .is_some_and(|expr| expr.starts_with("Some("));
1082 if optional {
1083 format!("{name}: val.{name}.as_ref().map(|v| v.to_string())")
1084 } else if already_some_wrapped {
1085 format!("{name}: Some(val.{name}.to_string())")
1086 } else {
1087 format!("{name}: val.{name}.to_string()")
1088 }
1089 }
1090 CoreWrapper::Arc => {
1091 if conversion.contains("{ inner: Arc::new(") {
1100 return conversion.replace("{ inner: Arc::new(v) }", "{ inner: v }").replace(
1101 &format!("{{ inner: Arc::new(val.{name}) }}"),
1102 &format!("{{ inner: val.{name} }}"),
1103 );
1104 }
1105 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1106 if optional {
1107 let simple_passthrough = format!("val.{name}");
1116 if expr == simple_passthrough {
1117 format!("{name}: {expr}.map(|v| (*v).clone().into())")
1118 } else {
1119 format!("{name}: {expr}")
1120 }
1121 } else {
1122 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
1123 format!("{name}: {unwrapped}")
1124 }
1125 } else {
1126 conversion.to_string()
1127 }
1128 }
1129 CoreWrapper::Bytes => {
1130 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1135 let already_converted_non_opt = expr == format!("val.{name}.to_vec().into()");
1136 let already_converted_opt = expr == format!("val.{name}.map(|v| v.to_vec().into())");
1137 if already_converted_non_opt || already_converted_opt {
1138 conversion.to_string()
1139 } else if optional {
1140 format!("{name}: {expr}.map(|v| v.to_vec().into())")
1141 } else if expr == format!("val.{name}") {
1142 format!("{name}: val.{name}.to_vec().into()")
1143 } else {
1144 conversion.to_string()
1145 }
1146 } else {
1147 conversion.to_string()
1148 }
1149 }
1150 CoreWrapper::ArcMutex => {
1151 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1153 if optional {
1154 format!("{name}: {expr}.map(|v| v.lock().unwrap().clone().into())")
1155 } else if expr == format!("val.{name}") {
1156 format!("{name}: val.{name}.lock().unwrap().clone().into()")
1157 } else {
1158 conversion.to_string()
1159 }
1160 } else {
1161 conversion.to_string()
1162 }
1163 }
1164 }
1165}