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 let base_conversion = field_conversion_from_core_cfg(
57 &field.name,
58 &field.ty,
59 field.optional,
60 field.sanitized,
61 opaque_types,
62 config,
63 );
64 let base_conversion = if field.is_boxed && matches!(&field.ty, TypeRef::Named(_)) {
66 if field.optional {
67 let src = format!("{}: val.{}.map(Into::into)", field.name, field.name);
69 let dst = format!("{}: val.{}.map(|v| (*v).into())", field.name, field.name);
70 if base_conversion == src { dst } else { base_conversion }
71 } else {
72 base_conversion.replace(&format!("val.{}", field.name), &format!("(*val.{})", field.name))
74 }
75 } else {
76 base_conversion
77 };
78 let base_conversion = if field.newtype_wrapper.is_some() {
84 match &field.ty {
85 TypeRef::Optional(_) => {
86 base_conversion.replace(
88 &format!("val.{}", field.name),
89 &format!("val.{}.map(|v| v.0)", field.name),
90 )
91 }
92 TypeRef::Vec(_) => {
93 base_conversion.replace(
95 &format!("val.{}", field.name),
96 &format!("val.{}.iter().map(|v| v.0).collect::<Vec<_>>()", field.name),
97 )
98 }
99 _ if field.optional => base_conversion.replace(
102 &format!("val.{}", field.name),
103 &format!("val.{}.map(|v| v.0)", field.name),
104 ),
105 _ => {
106 base_conversion.replace(&format!("val.{}", field.name), &format!("val.{}.0", field.name))
108 }
109 }
110 } else {
111 base_conversion
112 };
113 let is_flattened_optional = field.optional && matches!(field.ty, TypeRef::Optional(_));
119 let base_conversion = if is_flattened_optional {
120 if let TypeRef::Optional(inner) = &field.ty {
121 let inner_conv = field_conversion_from_core_cfg(
123 &field.name,
124 inner.as_ref(),
125 true,
126 field.sanitized,
127 opaque_types,
128 config,
129 );
130 inner_conv.replace(&format!("val.{}", field.name), &format!("val.{}.flatten()", field.name))
132 } else {
133 base_conversion
134 }
135 } else {
136 base_conversion
137 };
138 let needs_some_wrap = !is_flattened_optional
142 && ((optionalized && !field.optional)
143 || (config.option_duration_on_defaults
144 && typ.has_default
145 && !field.optional
146 && matches!(field.ty, TypeRef::Duration)));
147 let conversion = if needs_some_wrap {
148 if let Some(expr) = base_conversion.strip_prefix(&format!("{}: ", field.name)) {
150 format!("{}: Some({})", field.name, expr)
151 } else {
152 base_conversion
153 }
154 } else {
155 base_conversion
156 };
157 let is_opaque_no_wrapper_field = field.core_wrapper == CoreWrapper::None
161 && matches!(&field.ty, TypeRef::Named(n) if config
162 .opaque_types
163 .is_some_and(|opaque| opaque.contains(n.as_str())));
164 let conversion = if is_opaque_no_wrapper_field {
170 format!("{}: Default::default()", field.name)
171 } else if !field.sanitized || field.core_wrapper == alef_core::ir::CoreWrapper::Cow {
172 apply_core_wrapper_from_core(
173 &conversion,
174 &field.name,
175 &field.core_wrapper,
176 &field.vec_inner_core_wrapper,
177 field.optional,
178 )
179 } else {
180 conversion
181 };
182 if field.cfg.is_some() {
184 continue;
185 }
186 let binding_field = config.binding_field_name_owned(&typ.name, &field.name);
190 let conversion = if binding_field != field.name {
191 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
192 format!("{binding_field}: {expr}")
193 } else {
194 conversion
195 }
196 } else {
197 conversion
198 };
199 fields.push(conversion);
200 }
201
202 crate::template_env::render(
203 "conversions/core_to_binding_impl",
204 minijinja::context! {
205 core_path => core_path,
206 binding_name => binding_name,
207 is_newtype => false,
208 newtype_inner_expr => "",
209 fields => fields,
210 },
211 )
212}
213
214pub fn field_conversion_from_core(
217 name: &str,
218 ty: &TypeRef,
219 optional: bool,
220 sanitized: bool,
221 opaque_types: &AHashSet<String>,
222) -> String {
223 if sanitized {
227 if let TypeRef::Vec(inner) = ty {
230 if matches!(inner.as_ref(), TypeRef::Primitive(_)) {
231 if optional {
232 return format!(
233 "{name}: val.{name}.map(|t| {{ let arr: Vec<_> = [t.0, t.1].into_iter().map(|v| v as _).collect(); arr }})"
234 );
235 }
236 return format!("{name}: vec![val.{name}.0 as _, val.{name}.1 as _]");
237 }
238 }
239 if let TypeRef::Optional(opt_inner) = ty {
241 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
242 if matches!(vec_inner.as_ref(), TypeRef::Primitive(_)) {
243 return format!("{name}: val.{name}.map(|t| vec![t.0 as _, t.1 as _])");
244 }
245 }
246 }
247 if let TypeRef::Map(k, v) = ty {
249 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
250 if optional {
251 return format!(
252 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
253 );
254 }
255 return format!(
256 "{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()"
257 );
258 }
259 }
260 if let TypeRef::Vec(inner) = ty {
263 if matches!(inner.as_ref(), TypeRef::String) {
264 if optional {
265 return format!(
266 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
267 );
268 }
269 return format!("{name}: val.{name}.iter().map(|i| format!(\"{{:?}}\", i)).collect()");
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::String) {
276 return format!(
277 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
278 );
279 }
280 }
281 }
282 if matches!(ty, TypeRef::String) {
287 if optional {
288 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
289 }
290 return format!("{name}: format!(\"{{:?}}\", val.{name})");
291 }
292 if optional {
295 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
296 }
297 return format!("{name}: format!(\"{{:?}}\", val.{name})");
298 }
299 match ty {
300 TypeRef::Duration => {
302 if optional {
303 return format!("{name}: val.{name}.map(|d| d.as_millis() as u64)");
304 }
305 format!("{name}: val.{name}.as_millis() as u64")
306 }
307 TypeRef::Path => {
309 if optional {
310 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
311 } else {
312 format!("{name}: val.{name}.to_string_lossy().to_string()")
313 }
314 }
315 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
316 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
317 }
318 TypeRef::Char => {
320 if optional {
321 format!("{name}: val.{name}.map(|c| c.to_string())")
322 } else {
323 format!("{name}: val.{name}.to_string()")
324 }
325 }
326 TypeRef::Bytes => {
330 if optional {
331 format!("{name}: val.{name}.map(|v| v.to_vec().into())")
332 } else {
333 format!("{name}: val.{name}.to_vec().into()")
334 }
335 }
336 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
338 if optional {
339 format!("{name}: val.{name}.map(|v| {n} {{ inner: Arc::new(v) }})")
340 } else {
341 format!("{name}: {n} {{ inner: Arc::new(val.{name}) }}")
342 }
343 }
344 TypeRef::Json => {
346 if optional {
347 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
348 } else {
349 format!("{name}: val.{name}.to_string()")
350 }
351 }
352 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
353 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
354 }
355 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
356 if optional {
357 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.to_string()).collect())")
358 } else {
359 format!("{name}: val.{name}.iter().map(ToString::to_string).collect()")
360 }
361 }
362 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Optional(oi) if matches!(oi.as_ref(), TypeRef::Json)) => {
364 if optional {
365 format!(
366 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.as_ref().map(ToString::to_string)).collect())"
367 )
368 } else {
369 format!("{name}: val.{name}.iter().map(|i| i.as_ref().map(ToString::to_string)).collect()")
370 }
371 }
372 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Json) => {
377 if optional {
378 format!(
379 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
380 )
381 } else {
382 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()")
383 }
384 }
385 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
387 if optional {
388 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect())")
389 } else {
390 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v)).collect()")
391 }
392 }
393 TypeRef::Map(k, v) if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) => {
397 if optional {
398 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())")
399 } else {
400 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
401 }
402 }
403 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_)) => {
405 if optional {
406 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
407 } else {
408 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.into())).collect()")
409 }
410 }
411 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_))) =>
413 {
414 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
415 }
416 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
418 if optional {
419 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
420 } else {
421 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
422 }
423 }
424 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_))) =>
426 {
427 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
428 }
429 _ => field_conversion_to_core(name, ty, optional),
431 }
432}
433
434pub fn field_conversion_from_core_cfg(
436 name: &str,
437 ty: &TypeRef,
438 optional: bool,
439 sanitized: bool,
440 opaque_types: &AHashSet<String>,
441 config: &ConversionConfig,
442) -> String {
443 if sanitized {
448 if config.map_uses_jsvalue {
449 if let TypeRef::Map(k, v) = ty {
452 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
453 if optional {
454 return format!(
455 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
456 );
457 }
458 return format!(
459 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
460 );
461 }
462 }
463 if let TypeRef::Vec(inner) = ty {
465 if matches!(inner.as_ref(), TypeRef::Json) {
466 if optional {
467 return format!(
468 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
469 );
470 }
471 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
472 }
473 }
474 }
475 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
476 }
477
478 if let Some(untagged_names) = config.untagged_data_enum_names {
481 let direct_named = matches!(ty, TypeRef::Named(n) if untagged_names.contains(n));
482 let optional_named = matches!(ty, TypeRef::Optional(inner)
483 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
484 let vec_named = matches!(ty, TypeRef::Vec(inner)
485 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
486 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
487 if matches!(outer.as_ref(), TypeRef::Vec(inner)
488 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n))));
489 if direct_named {
490 if optional {
491 return format!(
492 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())"
493 );
494 }
495 return format!(
496 "{name}: serde_json::to_value(&val.{name}).unwrap_or(serde_json::Value::Null)"
497 );
498 }
499 if optional_named {
500 return format!(
501 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())"
502 );
503 }
504 if vec_named {
505 if optional {
506 return format!(
507 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
508 );
509 }
510 return format!(
511 "{name}: val.{name}.iter().filter_map(|x| serde_json::to_value(x).ok()).collect()"
512 );
513 }
514 if optional_vec_named {
515 return format!(
516 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
517 );
518 }
519 }
520
521 if config.vec_named_to_string {
525 if let TypeRef::Vec(inner) = ty {
526 if matches!(inner.as_ref(), TypeRef::Named(_)) {
527 if optional {
528 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok())");
529 }
530 return format!("{name}: serde_json::to_string(&val.{name}).unwrap_or_default()");
531 }
532 }
533 }
534
535 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
538 if optional {
539 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
540 }
541 return format!("{name}: format!(\"{{:?}}\", val.{name})");
542 }
543 if config.map_as_string {
544 if let TypeRef::Optional(inner) = ty {
545 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
546 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
547 }
548 }
549 }
550
551 if config.map_uses_jsvalue {
555 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
556 let is_map = matches!(ty, TypeRef::Map(_, _));
557 if is_map {
558 if optional {
559 return format!(
560 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
561 );
562 }
563 return format!(
564 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
565 );
566 }
567 if is_nested_vec {
568 if optional {
569 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
570 }
571 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
572 }
573 if let TypeRef::Optional(inner) = ty {
574 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
575 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
576 if is_inner_map {
577 return format!(
578 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
579 );
580 }
581 if is_inner_nested {
582 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
583 }
584 }
585 }
586
587 let prefix = config.type_name_prefix;
588 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
589
590 match ty {
591 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
593 let cast_to = binding_prim_str(p);
594 if optional {
595 format!("{name}: val.{name}.map(|v| v as {cast_to})")
596 } else {
597 format!("{name}: val.{name} as {cast_to}")
598 }
599 }
600 TypeRef::Optional(inner)
602 if config.cast_large_ints_to_i64
603 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
604 {
605 if let TypeRef::Primitive(p) = inner.as_ref() {
606 let cast_to = binding_prim_str(p);
607 format!("{name}: val.{name}.map(|v| v as {cast_to})")
608 } else {
609 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
610 }
611 }
612 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
614 if optional {
615 format!("{name}: val.{name}.map(|v| v as i32)")
616 } else {
617 format!("{name}: val.{name} as i32")
618 }
619 }
620 TypeRef::Optional(inner)
622 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
623 {
624 format!("{name}: val.{name}.map(|v| v as i32)")
625 }
626 TypeRef::Vec(inner)
628 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
629 {
630 if let TypeRef::Primitive(_p) = inner.as_ref() {
631 if optional {
632 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as i32).collect())")
633 } else {
634 format!("{name}: val.{name}.iter().map(|&v| v as i32).collect()")
635 }
636 } else {
637 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
638 }
639 }
640 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
642 if optional {
643 format!("{name}: val.{name}.map(|v| v as f64)")
644 } else {
645 format!("{name}: val.{name} as f64")
646 }
647 }
648 TypeRef::Optional(inner)
650 if config.cast_large_ints_to_f64
651 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
652 {
653 format!("{name}: val.{name}.map(|v| v as f64)")
654 }
655 TypeRef::Vec(inner)
657 if config.cast_large_ints_to_f64
658 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
659 {
660 if optional {
661 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
662 } else {
663 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
664 }
665 }
666 TypeRef::Optional(inner)
668 if config.cast_large_ints_to_f64
669 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
670 {
671 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
672 }
673 TypeRef::Vec(outer)
675 if config.cast_large_ints_to_f64
676 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
677 {
678 if optional {
679 format!(
680 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
681 )
682 } else {
683 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
684 }
685 }
686 TypeRef::Optional(inner)
688 if config.cast_large_ints_to_f64
689 && 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)))) =>
690 {
691 format!(
692 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
693 )
694 }
695 TypeRef::Map(_k, v)
697 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
698 {
699 if optional {
700 format!("{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as f64)).collect())")
701 } else {
702 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as f64)).collect()")
703 }
704 }
705 TypeRef::Duration if config.cast_large_ints_to_f64 => {
707 if optional {
708 format!("{name}: val.{name}.map(|d| d.as_millis() as f64)")
709 } else {
710 format!("{name}: val.{name}.as_millis() as f64")
711 }
712 }
713 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
715 if optional {
716 format!("{name}: val.{name}.map(|v| v as f64)")
717 } else {
718 format!("{name}: val.{name} as f64")
719 }
720 }
721 TypeRef::Duration if config.cast_large_ints_to_i64 => {
723 if optional {
724 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
725 } else {
726 format!("{name}: val.{name}.as_millis() as u64 as i64")
727 }
728 }
729 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
731 let prefixed = format!("{prefix}{n}");
732 if optional {
733 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
734 } else {
735 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
736 }
737 }
738 TypeRef::Named(n) if is_enum_string(n) => {
740 if optional {
743 format!(
744 "{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())"
745 )
746 } else {
747 format!(
748 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
749 )
750 }
751 }
752 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
754 if optional {
755 format!(
756 "{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())"
757 )
758 } else {
759 format!(
760 "{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()"
761 )
762 }
763 }
764 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
766 {
767 format!(
768 "{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())"
769 )
770 }
771 TypeRef::Vec(inner)
773 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
774 {
775 if optional {
776 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
777 } else {
778 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
779 }
780 }
781 TypeRef::Optional(inner)
783 if config.cast_f32_to_f64
784 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
785 {
786 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
787 }
788 TypeRef::Optional(inner)
790 if config.cast_large_ints_to_i64
791 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
792 {
793 if let TypeRef::Vec(vi) = inner.as_ref() {
794 if let TypeRef::Primitive(p) = vi.as_ref() {
795 let cast_to = binding_prim_str(p);
796 if sanitized {
797 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
799 } else {
800 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
801 }
802 } else {
803 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
804 }
805 } else {
806 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
807 }
808 }
809 TypeRef::Vec(outer)
811 if config.cast_f32_to_f64
812 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
813 {
814 if optional {
815 format!(
816 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
817 )
818 } else {
819 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
820 }
821 }
822 TypeRef::Optional(inner)
824 if config.cast_f32_to_f64
825 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
826 {
827 format!(
828 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
829 )
830 }
831 TypeRef::Optional(inner)
833 if config.cast_large_ints_to_i64
834 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
835 {
836 if let TypeRef::Primitive(p) = inner.as_ref() {
837 let cast_to = binding_prim_str(p);
838 format!("{name}: val.{name}.map(|v| v as {cast_to})")
839 } else {
840 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
841 }
842 }
843 TypeRef::Map(_k, v)
845 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
846 {
847 if let TypeRef::Primitive(p) = v.as_ref() {
848 let cast_to = binding_prim_str(p);
849 if optional {
850 format!(
851 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
852 )
853 } else {
854 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
855 }
856 } else {
857 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
858 }
859 }
860 TypeRef::Vec(inner)
862 if config.cast_large_ints_to_i64
863 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
864 {
865 if let TypeRef::Primitive(p) = inner.as_ref() {
866 let cast_to = binding_prim_str(p);
867 if sanitized {
868 if optional {
870 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
871 } else {
872 format!("{name}: {{ let (a, b) = val.{name}; vec![a as {cast_to}, b as {cast_to}] }}")
873 }
874 } else if optional {
875 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
876 } else {
877 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
878 }
879 } else {
880 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
881 }
882 }
883 TypeRef::Vec(outer)
885 if config.cast_large_ints_to_i64
886 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
887 {
888 if let TypeRef::Vec(inner) = outer.as_ref() {
889 if let TypeRef::Primitive(p) = inner.as_ref() {
890 let cast_to = binding_prim_str(p);
891 if optional {
892 format!(
893 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
894 )
895 } else {
896 format!(
897 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
898 )
899 }
900 } else {
901 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
902 }
903 } else {
904 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
905 }
906 }
907 TypeRef::Json if config.json_to_string => {
909 if optional {
910 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
911 } else {
912 format!("{name}: val.{name}.to_string()")
913 }
914 }
915 TypeRef::Json if config.json_as_value => {
917 format!("{name}: val.{name}")
918 }
919 TypeRef::Optional(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
920 format!("{name}: val.{name}")
921 }
922 TypeRef::Vec(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
923 if optional {
924 format!("{name}: Some(val.{name})")
925 } else {
926 format!("{name}: val.{name}")
927 }
928 }
929 TypeRef::Map(_k, v) if config.json_as_value && matches!(v.as_ref(), TypeRef::Json) => {
930 if optional {
931 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
932 } else {
933 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v)).collect()")
934 }
935 }
936 TypeRef::Json if config.map_uses_jsvalue => {
938 if optional {
939 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
940 } else {
941 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
942 }
943 }
944 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
946 if optional {
947 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
948 } else {
949 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
950 }
951 }
952 TypeRef::Optional(inner)
954 if config.map_uses_jsvalue
955 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
956 {
957 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
958 }
959 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
961 }
962}
963
964fn apply_core_wrapper_from_core(
967 conversion: &str,
968 name: &str,
969 core_wrapper: &CoreWrapper,
970 vec_inner_core_wrapper: &CoreWrapper,
971 optional: bool,
972) -> String {
973 if *vec_inner_core_wrapper == CoreWrapper::Arc {
975 return conversion
976 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
977 .replace(
978 "map(|v| v.into_iter().map(Into::into)",
979 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
980 );
981 }
982
983 match core_wrapper {
984 CoreWrapper::None => conversion.to_string(),
985 CoreWrapper::Cow => {
986 let prefix = format!("{name}: ");
993 let already_some_wrapped = conversion
994 .strip_prefix(&prefix)
995 .is_some_and(|expr| expr.starts_with("Some("));
996 if optional {
997 format!("{name}: val.{name}.as_ref().map(|v| v.to_string())")
998 } else if already_some_wrapped {
999 format!("{name}: Some(val.{name}.to_string())")
1000 } else {
1001 format!("{name}: val.{name}.to_string()")
1002 }
1003 }
1004 CoreWrapper::Arc => {
1005 if conversion.contains("{ inner: Arc::new(") {
1014 return conversion.replace("{ inner: Arc::new(v) }", "{ inner: v }").replace(
1015 &format!("{{ inner: Arc::new(val.{name}) }}"),
1016 &format!("{{ inner: val.{name} }}"),
1017 );
1018 }
1019 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1020 if optional {
1021 let simple_passthrough = format!("val.{name}");
1030 if expr == simple_passthrough {
1031 format!("{name}: {expr}.map(|v| (*v).clone().into())")
1032 } else {
1033 format!("{name}: {expr}")
1034 }
1035 } else {
1036 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
1037 format!("{name}: {unwrapped}")
1038 }
1039 } else {
1040 conversion.to_string()
1041 }
1042 }
1043 CoreWrapper::Bytes => {
1044 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1049 let already_converted_non_opt = expr == format!("val.{name}.to_vec().into()");
1050 let already_converted_opt = expr == format!("val.{name}.map(|v| v.to_vec().into())");
1051 if already_converted_non_opt || already_converted_opt {
1052 conversion.to_string()
1053 } else if optional {
1054 format!("{name}: {expr}.map(|v| v.to_vec().into())")
1055 } else if expr == format!("val.{name}") {
1056 format!("{name}: val.{name}.to_vec().into()")
1057 } else {
1058 conversion.to_string()
1059 }
1060 } else {
1061 conversion.to_string()
1062 }
1063 }
1064 CoreWrapper::ArcMutex => {
1065 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1067 if optional {
1068 format!("{name}: {expr}.map(|v| v.lock().unwrap().clone().into())")
1069 } else if expr == format!("val.{name}") {
1070 format!("{name}: val.{name}.lock().unwrap().clone().into()")
1071 } else {
1072 conversion.to_string()
1073 }
1074 } else {
1075 conversion.to_string()
1076 }
1077 }
1078 }
1079}