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() && !config.never_skip_cfg_field_names.contains(&field.name) {
185 continue;
186 }
187 let binding_field = config.binding_field_name_owned(&typ.name, &field.name);
191 let conversion = if binding_field != field.name {
192 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
193 format!("{binding_field}: {expr}")
194 } else {
195 conversion
196 }
197 } else {
198 conversion
199 };
200 fields.push(conversion);
201 }
202
203 crate::template_env::render(
204 "conversions/core_to_binding_impl",
205 minijinja::context! {
206 core_path => core_path,
207 binding_name => binding_name,
208 is_newtype => false,
209 newtype_inner_expr => "",
210 fields => fields,
211 },
212 )
213}
214
215pub fn field_conversion_from_core(
218 name: &str,
219 ty: &TypeRef,
220 optional: bool,
221 sanitized: bool,
222 opaque_types: &AHashSet<String>,
223) -> String {
224 if sanitized {
228 if let TypeRef::Vec(inner) = ty {
231 if matches!(inner.as_ref(), TypeRef::Primitive(_)) {
232 if optional {
233 return format!(
234 "{name}: val.{name}.map(|t| {{ let arr: Vec<_> = [t.0, t.1].into_iter().map(|v| v as _).collect(); arr }})"
235 );
236 }
237 return format!("{name}: vec![val.{name}.0 as _, val.{name}.1 as _]");
238 }
239 }
240 if let TypeRef::Optional(opt_inner) = ty {
242 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
243 if matches!(vec_inner.as_ref(), TypeRef::Primitive(_)) {
244 return format!("{name}: val.{name}.map(|t| vec![t.0 as _, t.1 as _])");
245 }
246 }
247 }
248 if let TypeRef::Map(k, v) = ty {
250 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
251 if optional {
252 return format!(
253 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
254 );
255 }
256 return format!(
257 "{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()"
258 );
259 }
260 }
261 if let TypeRef::Vec(inner) = ty {
264 if matches!(inner.as_ref(), TypeRef::String) {
265 if optional {
266 return format!(
267 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
268 );
269 }
270 return format!("{name}: val.{name}.iter().map(|i| format!(\"{{:?}}\", i)).collect()");
271 }
272 }
273 if let TypeRef::Optional(opt_inner) = ty {
275 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
276 if matches!(vec_inner.as_ref(), TypeRef::String) {
277 return format!(
278 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
279 );
280 }
281 }
282 }
283 if matches!(ty, TypeRef::String) {
288 if optional {
289 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
290 }
291 return format!("{name}: format!(\"{{:?}}\", val.{name})");
292 }
293 if optional {
296 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
297 }
298 return format!("{name}: format!(\"{{:?}}\", val.{name})");
299 }
300 match ty {
301 TypeRef::Duration => {
303 if optional {
304 return format!("{name}: val.{name}.map(|d| d.as_millis() as u64)");
305 }
306 format!("{name}: val.{name}.as_millis() as u64")
307 }
308 TypeRef::Path => {
310 if optional {
311 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
312 } else {
313 format!("{name}: val.{name}.to_string_lossy().to_string()")
314 }
315 }
316 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
317 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
318 }
319 TypeRef::Char => {
321 if optional {
322 format!("{name}: val.{name}.map(|c| c.to_string())")
323 } else {
324 format!("{name}: val.{name}.to_string()")
325 }
326 }
327 TypeRef::Bytes => {
331 if optional {
332 format!("{name}: val.{name}.map(|v| v.to_vec().into())")
333 } else {
334 format!("{name}: val.{name}.to_vec().into()")
335 }
336 }
337 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
339 if optional {
340 format!("{name}: val.{name}.map(|v| {n} {{ inner: Arc::new(v) }})")
341 } else {
342 format!("{name}: {n} {{ inner: Arc::new(val.{name}) }}")
343 }
344 }
345 TypeRef::Json => {
347 if optional {
348 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
349 } else {
350 format!("{name}: val.{name}.to_string()")
351 }
352 }
353 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
354 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
355 }
356 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
357 if optional {
358 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.to_string()).collect())")
359 } else {
360 format!("{name}: val.{name}.iter().map(ToString::to_string).collect()")
361 }
362 }
363 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Optional(oi) if matches!(oi.as_ref(), TypeRef::Json)) => {
365 if optional {
366 format!(
367 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.as_ref().map(ToString::to_string)).collect())"
368 )
369 } else {
370 format!("{name}: val.{name}.iter().map(|i| i.as_ref().map(ToString::to_string)).collect()")
371 }
372 }
373 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Json) => {
378 if optional {
379 format!(
380 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
381 )
382 } else {
383 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()")
384 }
385 }
386 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
388 if optional {
389 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect())")
390 } else {
391 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v)).collect()")
392 }
393 }
394 TypeRef::Map(k, v) if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) => {
398 if optional {
399 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())")
400 } else {
401 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
402 }
403 }
404 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Bytes) => {
407 if optional {
408 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect())")
409 } else {
410 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect()")
411 }
412 }
413 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_)) => {
415 if optional {
416 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
417 } else {
418 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.into())).collect()")
419 }
420 }
421 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_))) =>
423 {
424 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
425 }
426 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
428 if optional {
429 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
430 } else {
431 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
432 }
433 }
434 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_))) =>
436 {
437 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
438 }
439 _ => field_conversion_to_core(name, ty, optional),
441 }
442}
443
444pub fn field_conversion_from_core_cfg(
446 name: &str,
447 ty: &TypeRef,
448 optional: bool,
449 sanitized: bool,
450 opaque_types: &AHashSet<String>,
451 config: &ConversionConfig,
452) -> String {
453 if sanitized {
458 if config.map_uses_jsvalue {
459 if let TypeRef::Map(k, v) = ty {
462 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
463 if optional {
464 return format!(
465 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
466 );
467 }
468 return format!(
469 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
470 );
471 }
472 }
473 if let TypeRef::Vec(inner) = ty {
475 if matches!(inner.as_ref(), TypeRef::Json) {
476 if optional {
477 return format!(
478 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
479 );
480 }
481 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
482 }
483 }
484 }
485 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
486 }
487
488 if let Some(untagged_names) = config.untagged_data_enum_names {
491 let direct_named = matches!(ty, TypeRef::Named(n) if untagged_names.contains(n));
492 let optional_named = matches!(ty, TypeRef::Optional(inner)
493 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
494 let vec_named = matches!(ty, TypeRef::Vec(inner)
495 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
496 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
497 if matches!(outer.as_ref(), TypeRef::Vec(inner)
498 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n))));
499 if direct_named {
500 if optional {
501 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
502 }
503 return format!("{name}: serde_json::to_value(&val.{name}).unwrap_or(serde_json::Value::Null)");
504 }
505 if optional_named {
506 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
507 }
508 if vec_named {
509 if optional {
510 return format!(
511 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
512 );
513 }
514 return format!("{name}: val.{name}.iter().filter_map(|x| serde_json::to_value(x).ok()).collect()");
515 }
516 if optional_vec_named {
517 return format!(
518 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
519 );
520 }
521 }
522
523 if config.vec_named_to_string {
527 if let TypeRef::Vec(inner) = ty {
528 if matches!(inner.as_ref(), TypeRef::Named(_)) {
529 if optional {
530 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok())");
531 }
532 return format!("{name}: serde_json::to_string(&val.{name}).unwrap_or_default()");
533 }
534 }
535 }
536
537 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
540 if optional {
541 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
542 }
543 return format!("{name}: format!(\"{{:?}}\", val.{name})");
544 }
545 if config.map_as_string {
546 if let TypeRef::Optional(inner) = ty {
547 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
548 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
549 }
550 }
551 }
552
553 if config.map_uses_jsvalue {
557 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
558 let is_map = matches!(ty, TypeRef::Map(_, _));
559 if is_map {
560 if optional {
561 return format!(
562 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
563 );
564 }
565 return format!(
566 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
567 );
568 }
569 if is_nested_vec {
570 if optional {
571 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
572 }
573 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
574 }
575 if let TypeRef::Optional(inner) = ty {
576 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
577 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
578 if is_inner_map {
579 return format!(
580 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
581 );
582 }
583 if is_inner_nested {
584 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
585 }
586 }
587 }
588
589 let prefix = config.type_name_prefix;
590 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
591
592 match ty {
593 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
595 let cast_to = binding_prim_str(p);
596 if optional {
597 format!("{name}: val.{name}.map(|v| v as {cast_to})")
598 } else {
599 format!("{name}: val.{name} as {cast_to}")
600 }
601 }
602 TypeRef::Optional(inner)
604 if config.cast_large_ints_to_i64
605 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
606 {
607 if let TypeRef::Primitive(p) = inner.as_ref() {
608 let cast_to = binding_prim_str(p);
609 format!("{name}: val.{name}.map(|v| v as {cast_to})")
610 } else {
611 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
612 }
613 }
614 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
616 if optional {
617 format!("{name}: val.{name}.map(|v| v as i32)")
618 } else {
619 format!("{name}: val.{name} as i32")
620 }
621 }
622 TypeRef::Optional(inner)
624 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
625 {
626 format!("{name}: val.{name}.map(|v| v as i32)")
627 }
628 TypeRef::Vec(inner)
630 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
631 {
632 if let TypeRef::Primitive(_p) = inner.as_ref() {
633 if optional {
634 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as i32).collect())")
635 } else {
636 format!("{name}: val.{name}.iter().map(|&v| v as i32).collect()")
637 }
638 } else {
639 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
640 }
641 }
642 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
644 if optional {
645 format!("{name}: val.{name}.map(|v| v as f64)")
646 } else {
647 format!("{name}: val.{name} as f64")
648 }
649 }
650 TypeRef::Optional(inner)
652 if config.cast_large_ints_to_f64
653 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
654 {
655 format!("{name}: val.{name}.map(|v| v as f64)")
656 }
657 TypeRef::Vec(inner)
659 if config.cast_large_ints_to_f64
660 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
661 {
662 if optional {
663 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
664 } else {
665 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
666 }
667 }
668 TypeRef::Optional(inner)
670 if config.cast_large_ints_to_f64
671 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
672 {
673 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
674 }
675 TypeRef::Vec(outer)
677 if config.cast_large_ints_to_f64
678 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
679 {
680 if optional {
681 format!(
682 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
683 )
684 } else {
685 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
686 }
687 }
688 TypeRef::Optional(inner)
690 if config.cast_large_ints_to_f64
691 && 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)))) =>
692 {
693 format!(
694 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
695 )
696 }
697 TypeRef::Map(_k, v)
699 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
700 {
701 if optional {
702 format!("{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as f64)).collect())")
703 } else {
704 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as f64)).collect()")
705 }
706 }
707 TypeRef::Duration if config.cast_large_ints_to_f64 => {
709 if optional {
710 format!("{name}: val.{name}.map(|d| d.as_millis() as f64)")
711 } else {
712 format!("{name}: val.{name}.as_millis() as f64")
713 }
714 }
715 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
717 if optional {
718 format!("{name}: val.{name}.map(|v| v as f64)")
719 } else {
720 format!("{name}: val.{name} as f64")
721 }
722 }
723 TypeRef::Duration if config.cast_large_ints_to_i64 => {
725 if optional {
726 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
727 } else {
728 format!("{name}: val.{name}.as_millis() as u64 as i64")
729 }
730 }
731 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
733 let prefixed = format!("{prefix}{n}");
734 if optional {
735 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
736 } else {
737 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
738 }
739 }
740 TypeRef::Named(n) if is_enum_string(n) => {
742 if optional {
745 format!(
746 "{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())"
747 )
748 } else {
749 format!(
750 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
751 )
752 }
753 }
754 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
756 if optional {
757 format!(
758 "{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())"
759 )
760 } else {
761 format!(
762 "{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()"
763 )
764 }
765 }
766 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
768 {
769 format!(
770 "{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())"
771 )
772 }
773 TypeRef::Vec(inner)
775 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
776 {
777 if optional {
778 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
779 } else {
780 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
781 }
782 }
783 TypeRef::Optional(inner)
785 if config.cast_f32_to_f64
786 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
787 {
788 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
789 }
790 TypeRef::Optional(inner)
792 if config.cast_large_ints_to_i64
793 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
794 {
795 if let TypeRef::Vec(vi) = inner.as_ref() {
796 if let TypeRef::Primitive(p) = vi.as_ref() {
797 let cast_to = binding_prim_str(p);
798 if sanitized {
799 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
801 } else {
802 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
803 }
804 } else {
805 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
806 }
807 } else {
808 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
809 }
810 }
811 TypeRef::Vec(outer)
813 if config.cast_f32_to_f64
814 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
815 {
816 if optional {
817 format!(
818 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
819 )
820 } else {
821 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
822 }
823 }
824 TypeRef::Optional(inner)
826 if config.cast_f32_to_f64
827 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
828 {
829 format!(
830 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
831 )
832 }
833 TypeRef::Optional(inner)
835 if config.cast_large_ints_to_i64
836 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
837 {
838 if let TypeRef::Primitive(p) = inner.as_ref() {
839 let cast_to = binding_prim_str(p);
840 format!("{name}: val.{name}.map(|v| v as {cast_to})")
841 } else {
842 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
843 }
844 }
845 TypeRef::Map(_k, v)
847 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
848 {
849 if let TypeRef::Primitive(p) = v.as_ref() {
850 let cast_to = binding_prim_str(p);
851 if optional {
852 format!(
853 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
854 )
855 } else {
856 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
857 }
858 } else {
859 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
860 }
861 }
862 TypeRef::Vec(inner)
864 if config.cast_large_ints_to_i64
865 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
866 {
867 if let TypeRef::Primitive(p) = inner.as_ref() {
868 let cast_to = binding_prim_str(p);
869 if sanitized {
870 if optional {
872 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
873 } else {
874 format!("{name}: {{ let (a, b) = val.{name}; vec![a as {cast_to}, b as {cast_to}] }}")
875 }
876 } else if optional {
877 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
878 } else {
879 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
880 }
881 } else {
882 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
883 }
884 }
885 TypeRef::Vec(outer)
887 if config.cast_large_ints_to_i64
888 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
889 {
890 if let TypeRef::Vec(inner) = outer.as_ref() {
891 if let TypeRef::Primitive(p) = inner.as_ref() {
892 let cast_to = binding_prim_str(p);
893 if optional {
894 format!(
895 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
896 )
897 } else {
898 format!(
899 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
900 )
901 }
902 } else {
903 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
904 }
905 } else {
906 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
907 }
908 }
909 TypeRef::Json if config.json_to_string => {
911 if optional {
912 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
913 } else {
914 format!("{name}: val.{name}.to_string()")
915 }
916 }
917 TypeRef::Json if config.json_as_value => {
919 format!("{name}: val.{name}")
920 }
921 TypeRef::Optional(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
922 format!("{name}: val.{name}")
923 }
924 TypeRef::Vec(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
925 if optional {
926 format!("{name}: Some(val.{name})")
927 } else {
928 format!("{name}: val.{name}")
929 }
930 }
931 TypeRef::Map(_k, v) if config.json_as_value && matches!(v.as_ref(), TypeRef::Json) => {
932 if optional {
933 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
934 } else {
935 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v)).collect()")
936 }
937 }
938 TypeRef::Json if config.map_uses_jsvalue => {
940 if optional {
941 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
942 } else {
943 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
944 }
945 }
946 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
948 if optional {
949 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
950 } else {
951 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
952 }
953 }
954 TypeRef::Optional(inner)
956 if config.map_uses_jsvalue
957 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
958 {
959 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
960 }
961 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
963 }
964}
965
966fn apply_core_wrapper_from_core(
969 conversion: &str,
970 name: &str,
971 core_wrapper: &CoreWrapper,
972 vec_inner_core_wrapper: &CoreWrapper,
973 optional: bool,
974) -> String {
975 if *vec_inner_core_wrapper == CoreWrapper::Arc {
977 return conversion
978 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
979 .replace(
980 "map(|v| v.into_iter().map(Into::into)",
981 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
982 );
983 }
984
985 match core_wrapper {
986 CoreWrapper::None => conversion.to_string(),
987 CoreWrapper::Cow => {
988 let prefix = format!("{name}: ");
995 let already_some_wrapped = conversion
996 .strip_prefix(&prefix)
997 .is_some_and(|expr| expr.starts_with("Some("));
998 if optional {
999 format!("{name}: val.{name}.as_ref().map(|v| v.to_string())")
1000 } else if already_some_wrapped {
1001 format!("{name}: Some(val.{name}.to_string())")
1002 } else {
1003 format!("{name}: val.{name}.to_string()")
1004 }
1005 }
1006 CoreWrapper::Arc => {
1007 if conversion.contains("{ inner: Arc::new(") {
1016 return conversion.replace("{ inner: Arc::new(v) }", "{ inner: v }").replace(
1017 &format!("{{ inner: Arc::new(val.{name}) }}"),
1018 &format!("{{ inner: val.{name} }}"),
1019 );
1020 }
1021 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1022 if optional {
1023 let simple_passthrough = format!("val.{name}");
1032 if expr == simple_passthrough {
1033 format!("{name}: {expr}.map(|v| (*v).clone().into())")
1034 } else {
1035 format!("{name}: {expr}")
1036 }
1037 } else {
1038 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
1039 format!("{name}: {unwrapped}")
1040 }
1041 } else {
1042 conversion.to_string()
1043 }
1044 }
1045 CoreWrapper::Bytes => {
1046 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1051 let already_converted_non_opt = expr == format!("val.{name}.to_vec().into()");
1052 let already_converted_opt = expr == format!("val.{name}.map(|v| v.to_vec().into())");
1053 if already_converted_non_opt || already_converted_opt {
1054 conversion.to_string()
1055 } else if optional {
1056 format!("{name}: {expr}.map(|v| v.to_vec().into())")
1057 } else if expr == format!("val.{name}") {
1058 format!("{name}: val.{name}.to_vec().into()")
1059 } else {
1060 conversion.to_string()
1061 }
1062 } else {
1063 conversion.to_string()
1064 }
1065 }
1066 CoreWrapper::ArcMutex => {
1067 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1069 if optional {
1070 format!("{name}: {expr}.map(|v| v.lock().unwrap().clone().into())")
1071 } else if expr == format!("val.{name}") {
1072 format!("{name}: val.{name}.lock().unwrap().clone().into()")
1073 } else {
1074 conversion.to_string()
1075 }
1076 } else {
1077 conversion.to_string()
1078 }
1079 }
1080 }
1081}