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 !config.exclude_types.is_empty()
52 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types)
53 {
54 continue;
55 }
56 if field.cfg.is_some()
61 && !config.never_skip_cfg_field_names.contains(&field.name)
62 && config.strip_cfg_fields_from_binding_struct
63 {
64 continue;
65 }
66 let base_conversion = field_conversion_from_core_cfg(
67 &field.name,
68 &field.ty,
69 field.optional,
70 field.sanitized,
71 opaque_types,
72 config,
73 );
74 let base_conversion = if field.is_boxed && matches!(&field.ty, TypeRef::Named(_)) {
76 if field.optional {
77 let src = format!("{}: val.{}.map(Into::into)", field.name, field.name);
79 let dst = format!("{}: val.{}.map(|v| (*v).into())", field.name, field.name);
80 if base_conversion == src { dst } else { base_conversion }
81 } else {
82 base_conversion.replace(&format!("val.{}", field.name), &format!("(*val.{})", field.name))
84 }
85 } else {
86 base_conversion
87 };
88 let base_conversion = if field.newtype_wrapper.is_some() {
94 match &field.ty {
95 TypeRef::Optional(_) => {
96 base_conversion.replace(
98 &format!("val.{}", field.name),
99 &format!("val.{}.map(|v| v.0)", field.name),
100 )
101 }
102 TypeRef::Vec(_) => {
103 base_conversion.replace(
105 &format!("val.{}", field.name),
106 &format!("val.{}.iter().map(|v| v.0).collect::<Vec<_>>()", field.name),
107 )
108 }
109 _ if field.optional => base_conversion.replace(
112 &format!("val.{}", field.name),
113 &format!("val.{}.map(|v| v.0)", field.name),
114 ),
115 _ => {
116 base_conversion.replace(&format!("val.{}", field.name), &format!("val.{}.0", field.name))
118 }
119 }
120 } else {
121 base_conversion
122 };
123 let is_flattened_optional = field.optional && matches!(field.ty, TypeRef::Optional(_));
129 let base_conversion = if is_flattened_optional {
130 if let TypeRef::Optional(inner) = &field.ty {
131 let inner_conv = field_conversion_from_core_cfg(
133 &field.name,
134 inner.as_ref(),
135 true,
136 field.sanitized,
137 opaque_types,
138 config,
139 );
140 inner_conv.replace(&format!("val.{}", field.name), &format!("val.{}.flatten()", field.name))
142 } else {
143 base_conversion
144 }
145 } else {
146 base_conversion
147 };
148 let needs_some_wrap = !is_flattened_optional
152 && ((optionalized && !field.optional)
153 || (config.option_duration_on_defaults
154 && typ.has_default
155 && !field.optional
156 && matches!(field.ty, TypeRef::Duration)));
157 let conversion = if needs_some_wrap {
158 if let Some(expr) = base_conversion.strip_prefix(&format!("{}: ", field.name)) {
160 format!("{}: Some({})", field.name, expr)
161 } else {
162 base_conversion
163 }
164 } else {
165 base_conversion
166 };
167 let is_opaque_no_wrapper_field = field.core_wrapper == CoreWrapper::None
171 && matches!(&field.ty, TypeRef::Named(n) if config
172 .opaque_types
173 .is_some_and(|opaque| opaque.contains(n.as_str())));
174 let conversion = if is_opaque_no_wrapper_field {
180 format!("{}: Default::default()", field.name)
181 } else if !field.sanitized || field.core_wrapper == alef_core::ir::CoreWrapper::Cow {
182 apply_core_wrapper_from_core(
183 &conversion,
184 &field.name,
185 &field.core_wrapper,
186 &field.vec_inner_core_wrapper,
187 field.optional,
188 )
189 } else {
190 conversion
191 };
192 let binding_field = config.binding_field_name_owned(&typ.name, &field.name);
196 let conversion = if binding_field != field.name {
197 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
198 format!("{binding_field}: {expr}")
199 } else {
200 conversion
201 }
202 } else {
203 conversion
204 };
205 let field_is_trait_bridge = field.cfg.is_some() && config.never_skip_cfg_field_names.contains(&field.name) && {
211 let opaque_vec: Vec<String> = opaque_types.iter().cloned().collect();
212 crate::generators::structs::field_references_opaque_type(&field.ty, &opaque_vec)
213 };
214 let conversion = if field_is_trait_bridge {
215 format!("{}: Default::default()", binding_field)
216 } else {
217 conversion
218 };
219 fields.push(conversion);
220 }
221
222 crate::template_env::render(
223 "conversions/core_to_binding_impl",
224 minijinja::context! {
225 core_path => core_path,
226 binding_name => binding_name,
227 is_newtype => false,
228 newtype_inner_expr => "",
229 fields => fields,
230 },
231 )
232}
233
234pub fn field_conversion_from_core(
237 name: &str,
238 ty: &TypeRef,
239 optional: bool,
240 sanitized: bool,
241 opaque_types: &AHashSet<String>,
242) -> String {
243 if sanitized {
247 if let TypeRef::Vec(inner) = ty {
250 if matches!(inner.as_ref(), TypeRef::Primitive(_)) {
251 if optional {
252 return format!(
253 "{name}: val.{name}.map(|t| {{ let arr: Vec<_> = [t.0, t.1].into_iter().map(|v| v as _).collect(); arr }})"
254 );
255 }
256 return format!("{name}: vec![val.{name}.0 as _, val.{name}.1 as _]");
257 }
258 }
259 if let TypeRef::Optional(opt_inner) = ty {
261 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
262 if matches!(vec_inner.as_ref(), TypeRef::Primitive(_)) {
263 return format!("{name}: val.{name}.map(|t| vec![t.0 as _, t.1 as _])");
264 }
265 }
266 }
267 if let TypeRef::Map(k, v) = ty {
269 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
270 if optional {
271 return format!(
272 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
273 );
274 }
275 return format!(
276 "{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()"
277 );
278 }
279 }
280 if let TypeRef::Vec(inner) = ty {
283 if matches!(inner.as_ref(), TypeRef::String) {
284 if optional {
285 return format!(
286 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
287 );
288 }
289 return format!("{name}: val.{name}.iter().map(|i| format!(\"{{:?}}\", i)).collect()");
290 }
291 }
292 if let TypeRef::Optional(opt_inner) = ty {
294 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
295 if matches!(vec_inner.as_ref(), TypeRef::String) {
296 return format!(
297 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
298 );
299 }
300 }
301 }
302 if matches!(ty, TypeRef::String) {
307 if optional {
308 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
309 }
310 return format!("{name}: format!(\"{{:?}}\", val.{name})");
311 }
312 if optional {
315 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
316 }
317 return format!("{name}: format!(\"{{:?}}\", val.{name})");
318 }
319 match ty {
320 TypeRef::Duration => {
322 if optional {
323 return format!("{name}: val.{name}.map(|d| d.as_millis() as u64)");
324 }
325 format!("{name}: val.{name}.as_millis() as u64")
326 }
327 TypeRef::Path => {
329 if optional {
330 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
331 } else {
332 format!("{name}: val.{name}.to_string_lossy().to_string()")
333 }
334 }
335 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
336 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
337 }
338 TypeRef::Char => {
340 if optional {
341 format!("{name}: val.{name}.map(|c| c.to_string())")
342 } else {
343 format!("{name}: val.{name}.to_string()")
344 }
345 }
346 TypeRef::Bytes => {
350 if optional {
351 format!("{name}: val.{name}.map(|v| v.to_vec().into())")
352 } else {
353 format!("{name}: val.{name}.to_vec().into()")
354 }
355 }
356 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
358 if optional {
359 format!("{name}: val.{name}.map(|v| {n} {{ inner: Arc::new(v) }})")
360 } else {
361 format!("{name}: {n} {{ inner: Arc::new(val.{name}) }}")
362 }
363 }
364 TypeRef::Json => {
366 if optional {
367 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
368 } else {
369 format!("{name}: val.{name}.to_string()")
370 }
371 }
372 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
373 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
374 }
375 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
376 if optional {
377 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.to_string()).collect())")
378 } else {
379 format!("{name}: val.{name}.iter().map(ToString::to_string).collect()")
380 }
381 }
382 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Optional(oi) if matches!(oi.as_ref(), TypeRef::Json)) => {
384 if optional {
385 format!(
386 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.as_ref().map(ToString::to_string)).collect())"
387 )
388 } else {
389 format!("{name}: val.{name}.iter().map(|i| i.as_ref().map(ToString::to_string)).collect()")
390 }
391 }
392 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Json) => {
397 if optional {
398 format!(
399 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
400 )
401 } else {
402 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()")
403 }
404 }
405 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
407 if optional {
408 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect())")
409 } else {
410 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v)).collect()")
411 }
412 }
413 TypeRef::Map(k, v) if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) => {
417 if optional {
418 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())")
419 } else {
420 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
421 }
422 }
423 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Bytes) => {
426 if optional {
427 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect())")
428 } else {
429 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect()")
430 }
431 }
432 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_)) => {
434 if optional {
435 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
436 } else {
437 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.into())).collect()")
438 }
439 }
440 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_))) =>
442 {
443 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
444 }
445 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
447 if optional {
448 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
449 } else {
450 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
451 }
452 }
453 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_))) =>
455 {
456 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
457 }
458 _ => field_conversion_to_core(name, ty, optional),
460 }
461}
462
463pub fn field_conversion_from_core_cfg(
465 name: &str,
466 ty: &TypeRef,
467 optional: bool,
468 sanitized: bool,
469 opaque_types: &AHashSet<String>,
470 config: &ConversionConfig,
471) -> String {
472 if sanitized {
477 if config.map_uses_jsvalue {
478 if let TypeRef::Map(k, v) = ty {
481 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
482 if optional {
483 return format!(
484 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
485 );
486 }
487 return format!(
488 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
489 );
490 }
491 }
492 if let TypeRef::Vec(inner) = ty {
494 if matches!(inner.as_ref(), TypeRef::Json) {
495 if optional {
496 return format!(
497 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
498 );
499 }
500 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
501 }
502 }
503 }
504 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
505 }
506
507 if let Some(untagged_names) = config.untagged_data_enum_names {
510 let direct_named = matches!(ty, TypeRef::Named(n) if untagged_names.contains(n));
511 let optional_named = matches!(ty, TypeRef::Optional(inner)
512 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
513 let vec_named = matches!(ty, TypeRef::Vec(inner)
514 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
515 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
516 if matches!(outer.as_ref(), TypeRef::Vec(inner)
517 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n))));
518 if direct_named {
519 if optional {
520 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
521 }
522 return format!("{name}: serde_json::to_value(&val.{name}).unwrap_or(serde_json::Value::Null)");
523 }
524 if optional_named {
525 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
526 }
527 if vec_named {
528 if optional {
529 return format!(
530 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
531 );
532 }
533 return format!("{name}: val.{name}.iter().filter_map(|x| serde_json::to_value(x).ok()).collect()");
534 }
535 if optional_vec_named {
536 return format!(
537 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
538 );
539 }
540 }
541
542 if config.vec_named_to_string {
546 if let TypeRef::Vec(inner) = ty {
547 if matches!(inner.as_ref(), TypeRef::Named(_)) {
548 if optional {
549 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok())");
550 }
551 return format!("{name}: serde_json::to_string(&val.{name}).unwrap_or_default()");
552 }
553 }
554 }
555
556 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
559 if optional {
560 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
561 }
562 return format!("{name}: format!(\"{{:?}}\", val.{name})");
563 }
564 if config.map_as_string {
565 if let TypeRef::Optional(inner) = ty {
566 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
567 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
568 }
569 }
570 }
571
572 if config.map_uses_jsvalue {
576 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
577 let is_map = matches!(ty, TypeRef::Map(_, _));
578 if is_map {
579 if optional {
580 return format!(
581 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
582 );
583 }
584 return format!(
585 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
586 );
587 }
588 if is_nested_vec {
589 if optional {
590 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
591 }
592 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
593 }
594 if let TypeRef::Optional(inner) = ty {
595 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
596 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
597 if is_inner_map {
598 return format!(
599 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
600 );
601 }
602 if is_inner_nested {
603 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
604 }
605 }
606 }
607
608 let prefix = config.type_name_prefix;
609 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
610
611 match ty {
612 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
614 let cast_to = binding_prim_str(p);
615 if optional {
616 format!("{name}: val.{name}.map(|v| v as {cast_to})")
617 } else {
618 format!("{name}: val.{name} as {cast_to}")
619 }
620 }
621 TypeRef::Optional(inner)
623 if config.cast_large_ints_to_i64
624 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
625 {
626 if let TypeRef::Primitive(p) = inner.as_ref() {
627 let cast_to = binding_prim_str(p);
628 format!("{name}: val.{name}.map(|v| v as {cast_to})")
629 } else {
630 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
631 }
632 }
633 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
635 if optional {
636 format!("{name}: val.{name}.map(|v| v as i32)")
637 } else {
638 format!("{name}: val.{name} as i32")
639 }
640 }
641 TypeRef::Optional(inner)
643 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
644 {
645 format!("{name}: val.{name}.map(|v| v as i32)")
646 }
647 TypeRef::Vec(inner)
649 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
650 {
651 if let TypeRef::Primitive(_p) = inner.as_ref() {
652 if optional {
653 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as i32).collect())")
654 } else {
655 format!("{name}: val.{name}.iter().map(|&v| v as i32).collect()")
656 }
657 } else {
658 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
659 }
660 }
661 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
663 if optional {
664 format!("{name}: val.{name}.map(|v| v as f64)")
665 } else {
666 format!("{name}: val.{name} as f64")
667 }
668 }
669 TypeRef::Optional(inner)
671 if config.cast_large_ints_to_f64
672 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
673 {
674 format!("{name}: val.{name}.map(|v| v as f64)")
675 }
676 TypeRef::Vec(inner)
678 if config.cast_large_ints_to_f64
679 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
680 {
681 if optional {
682 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
683 } else {
684 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
685 }
686 }
687 TypeRef::Optional(inner)
689 if config.cast_large_ints_to_f64
690 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
691 {
692 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
693 }
694 TypeRef::Vec(outer)
696 if config.cast_large_ints_to_f64
697 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
698 {
699 if optional {
700 format!(
701 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
702 )
703 } else {
704 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
705 }
706 }
707 TypeRef::Optional(inner)
709 if config.cast_large_ints_to_f64
710 && 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)))) =>
711 {
712 format!(
713 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
714 )
715 }
716 TypeRef::Map(_k, v)
718 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
719 {
720 if optional {
721 format!("{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as f64)).collect())")
722 } else {
723 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as f64)).collect()")
724 }
725 }
726 TypeRef::Duration if config.cast_large_ints_to_f64 => {
728 if optional {
729 format!("{name}: val.{name}.map(|d| d.as_millis() as f64)")
730 } else {
731 format!("{name}: val.{name}.as_millis() as f64")
732 }
733 }
734 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
736 if optional {
737 format!("{name}: val.{name}.map(|v| v as f64)")
738 } else {
739 format!("{name}: val.{name} as f64")
740 }
741 }
742 TypeRef::Duration if config.cast_large_ints_to_i64 => {
744 if optional {
745 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
746 } else {
747 format!("{name}: val.{name}.as_millis() as u64 as i64")
748 }
749 }
750 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
752 let prefixed = format!("{prefix}{n}");
753 if optional {
754 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
755 } else {
756 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
757 }
758 }
759 TypeRef::Named(n) if is_enum_string(n) => {
761 if optional {
764 format!(
765 "{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())"
766 )
767 } else {
768 format!(
769 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
770 )
771 }
772 }
773 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
775 if optional {
776 format!(
777 "{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())"
778 )
779 } else {
780 format!(
781 "{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()"
782 )
783 }
784 }
785 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
787 {
788 format!(
789 "{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())"
790 )
791 }
792 TypeRef::Vec(inner)
794 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
795 {
796 if optional {
797 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
798 } else {
799 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
800 }
801 }
802 TypeRef::Optional(inner)
804 if config.cast_f32_to_f64
805 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
806 {
807 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
808 }
809 TypeRef::Optional(inner)
811 if config.cast_large_ints_to_i64
812 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
813 {
814 if let TypeRef::Vec(vi) = inner.as_ref() {
815 if let TypeRef::Primitive(p) = vi.as_ref() {
816 let cast_to = binding_prim_str(p);
817 if sanitized {
818 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
820 } else {
821 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
822 }
823 } else {
824 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
825 }
826 } else {
827 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
828 }
829 }
830 TypeRef::Vec(outer)
832 if config.cast_f32_to_f64
833 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
834 {
835 if optional {
836 format!(
837 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
838 )
839 } else {
840 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
841 }
842 }
843 TypeRef::Optional(inner)
845 if config.cast_f32_to_f64
846 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
847 {
848 format!(
849 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
850 )
851 }
852 TypeRef::Optional(inner)
854 if config.cast_large_ints_to_i64
855 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
856 {
857 if let TypeRef::Primitive(p) = inner.as_ref() {
858 let cast_to = binding_prim_str(p);
859 format!("{name}: val.{name}.map(|v| v as {cast_to})")
860 } else {
861 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
862 }
863 }
864 TypeRef::Map(_k, v)
866 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
867 {
868 if let TypeRef::Primitive(p) = v.as_ref() {
869 let cast_to = binding_prim_str(p);
870 if optional {
871 format!(
872 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
873 )
874 } else {
875 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
876 }
877 } else {
878 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
879 }
880 }
881 TypeRef::Vec(inner)
883 if config.cast_large_ints_to_i64
884 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
885 {
886 if let TypeRef::Primitive(p) = inner.as_ref() {
887 let cast_to = binding_prim_str(p);
888 if sanitized {
889 if optional {
891 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
892 } else {
893 format!("{name}: {{ let (a, b) = val.{name}; vec![a as {cast_to}, b as {cast_to}] }}")
894 }
895 } else if optional {
896 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
897 } else {
898 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
899 }
900 } else {
901 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
902 }
903 }
904 TypeRef::Vec(outer)
906 if config.cast_large_ints_to_i64
907 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
908 {
909 if let TypeRef::Vec(inner) = outer.as_ref() {
910 if let TypeRef::Primitive(p) = inner.as_ref() {
911 let cast_to = binding_prim_str(p);
912 if optional {
913 format!(
914 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
915 )
916 } else {
917 format!(
918 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
919 )
920 }
921 } else {
922 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
923 }
924 } else {
925 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
926 }
927 }
928 TypeRef::Json if config.json_to_string => {
930 if optional {
931 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
932 } else {
933 format!("{name}: val.{name}.to_string()")
934 }
935 }
936 TypeRef::Json if config.json_as_value => {
938 format!("{name}: val.{name}")
939 }
940 TypeRef::Optional(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
941 format!("{name}: val.{name}")
942 }
943 TypeRef::Vec(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
944 if optional {
945 format!("{name}: Some(val.{name})")
946 } else {
947 format!("{name}: val.{name}")
948 }
949 }
950 TypeRef::Map(_k, v) if config.json_as_value && matches!(v.as_ref(), TypeRef::Json) => {
951 if optional {
952 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
953 } else {
954 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v)).collect()")
955 }
956 }
957 TypeRef::Json if config.map_uses_jsvalue => {
959 if optional {
960 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
961 } else {
962 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
963 }
964 }
965 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
967 if optional {
968 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
969 } else {
970 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
971 }
972 }
973 TypeRef::Optional(inner)
975 if config.map_uses_jsvalue
976 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
977 {
978 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
979 }
980 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
982 }
983}
984
985fn apply_core_wrapper_from_core(
988 conversion: &str,
989 name: &str,
990 core_wrapper: &CoreWrapper,
991 vec_inner_core_wrapper: &CoreWrapper,
992 optional: bool,
993) -> String {
994 if *vec_inner_core_wrapper == CoreWrapper::Arc {
996 return conversion
997 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
998 .replace(
999 "map(|v| v.into_iter().map(Into::into)",
1000 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
1001 );
1002 }
1003
1004 match core_wrapper {
1005 CoreWrapper::None => conversion.to_string(),
1006 CoreWrapper::Cow => {
1007 let prefix = format!("{name}: ");
1014 let already_some_wrapped = conversion
1015 .strip_prefix(&prefix)
1016 .is_some_and(|expr| expr.starts_with("Some("));
1017 if optional {
1018 format!("{name}: val.{name}.as_ref().map(|v| v.to_string())")
1019 } else if already_some_wrapped {
1020 format!("{name}: Some(val.{name}.to_string())")
1021 } else {
1022 format!("{name}: val.{name}.to_string()")
1023 }
1024 }
1025 CoreWrapper::Arc => {
1026 if conversion.contains("{ inner: Arc::new(") {
1035 return conversion.replace("{ inner: Arc::new(v) }", "{ inner: v }").replace(
1036 &format!("{{ inner: Arc::new(val.{name}) }}"),
1037 &format!("{{ inner: val.{name} }}"),
1038 );
1039 }
1040 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1041 if optional {
1042 let simple_passthrough = format!("val.{name}");
1051 if expr == simple_passthrough {
1052 format!("{name}: {expr}.map(|v| (*v).clone().into())")
1053 } else {
1054 format!("{name}: {expr}")
1055 }
1056 } else {
1057 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
1058 format!("{name}: {unwrapped}")
1059 }
1060 } else {
1061 conversion.to_string()
1062 }
1063 }
1064 CoreWrapper::Bytes => {
1065 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1070 let already_converted_non_opt = expr == format!("val.{name}.to_vec().into()");
1071 let already_converted_opt = expr == format!("val.{name}.map(|v| v.to_vec().into())");
1072 if already_converted_non_opt || already_converted_opt {
1073 conversion.to_string()
1074 } else if optional {
1075 format!("{name}: {expr}.map(|v| v.to_vec().into())")
1076 } else if expr == format!("val.{name}") {
1077 format!("{name}: val.{name}.to_vec().into()")
1078 } else {
1079 conversion.to_string()
1080 }
1081 } else {
1082 conversion.to_string()
1083 }
1084 }
1085 CoreWrapper::ArcMutex => {
1086 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1088 if optional {
1089 format!("{name}: {expr}.map(|v| v.lock().unwrap().clone().into())")
1090 } else if expr == format!("val.{name}") {
1091 format!("{name}: val.{name}.lock().unwrap().clone().into()")
1092 } else {
1093 conversion.to_string()
1094 }
1095 } else {
1096 conversion.to_string()
1097 }
1098 }
1099 }
1100}