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::Bytes) => {
406 if optional {
407 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect())")
408 } else {
409 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect()")
410 }
411 }
412 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_)) => {
414 if optional {
415 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
416 } else {
417 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.into())).collect()")
418 }
419 }
420 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_))) =>
422 {
423 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
424 }
425 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
427 if optional {
428 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
429 } else {
430 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
431 }
432 }
433 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_))) =>
435 {
436 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
437 }
438 _ => field_conversion_to_core(name, ty, optional),
440 }
441}
442
443pub fn field_conversion_from_core_cfg(
445 name: &str,
446 ty: &TypeRef,
447 optional: bool,
448 sanitized: bool,
449 opaque_types: &AHashSet<String>,
450 config: &ConversionConfig,
451) -> String {
452 if sanitized {
457 if config.map_uses_jsvalue {
458 if let TypeRef::Map(k, v) = ty {
461 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
462 if optional {
463 return format!(
464 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
465 );
466 }
467 return format!(
468 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
469 );
470 }
471 }
472 if let TypeRef::Vec(inner) = ty {
474 if matches!(inner.as_ref(), TypeRef::Json) {
475 if optional {
476 return format!(
477 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
478 );
479 }
480 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
481 }
482 }
483 }
484 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
485 }
486
487 if let Some(untagged_names) = config.untagged_data_enum_names {
490 let direct_named = matches!(ty, TypeRef::Named(n) if untagged_names.contains(n));
491 let optional_named = matches!(ty, TypeRef::Optional(inner)
492 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
493 let vec_named = matches!(ty, TypeRef::Vec(inner)
494 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
495 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
496 if matches!(outer.as_ref(), TypeRef::Vec(inner)
497 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n))));
498 if direct_named {
499 if optional {
500 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
501 }
502 return format!("{name}: serde_json::to_value(&val.{name}).unwrap_or(serde_json::Value::Null)");
503 }
504 if optional_named {
505 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
506 }
507 if vec_named {
508 if optional {
509 return format!(
510 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
511 );
512 }
513 return format!("{name}: val.{name}.iter().filter_map(|x| serde_json::to_value(x).ok()).collect()");
514 }
515 if optional_vec_named {
516 return format!(
517 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
518 );
519 }
520 }
521
522 if config.vec_named_to_string {
526 if let TypeRef::Vec(inner) = ty {
527 if matches!(inner.as_ref(), TypeRef::Named(_)) {
528 if optional {
529 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok())");
530 }
531 return format!("{name}: serde_json::to_string(&val.{name}).unwrap_or_default()");
532 }
533 }
534 }
535
536 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
539 if optional {
540 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
541 }
542 return format!("{name}: format!(\"{{:?}}\", val.{name})");
543 }
544 if config.map_as_string {
545 if let TypeRef::Optional(inner) = ty {
546 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
547 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
548 }
549 }
550 }
551
552 if config.map_uses_jsvalue {
556 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
557 let is_map = matches!(ty, TypeRef::Map(_, _));
558 if is_map {
559 if optional {
560 return format!(
561 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
562 );
563 }
564 return format!(
565 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
566 );
567 }
568 if is_nested_vec {
569 if optional {
570 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
571 }
572 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
573 }
574 if let TypeRef::Optional(inner) = ty {
575 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
576 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
577 if is_inner_map {
578 return format!(
579 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
580 );
581 }
582 if is_inner_nested {
583 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
584 }
585 }
586 }
587
588 let prefix = config.type_name_prefix;
589 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
590
591 match ty {
592 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
594 let cast_to = binding_prim_str(p);
595 if optional {
596 format!("{name}: val.{name}.map(|v| v as {cast_to})")
597 } else {
598 format!("{name}: val.{name} as {cast_to}")
599 }
600 }
601 TypeRef::Optional(inner)
603 if config.cast_large_ints_to_i64
604 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
605 {
606 if let TypeRef::Primitive(p) = inner.as_ref() {
607 let cast_to = binding_prim_str(p);
608 format!("{name}: val.{name}.map(|v| v as {cast_to})")
609 } else {
610 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
611 }
612 }
613 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
615 if optional {
616 format!("{name}: val.{name}.map(|v| v as i32)")
617 } else {
618 format!("{name}: val.{name} as i32")
619 }
620 }
621 TypeRef::Optional(inner)
623 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
624 {
625 format!("{name}: val.{name}.map(|v| v as i32)")
626 }
627 TypeRef::Vec(inner)
629 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
630 {
631 if let TypeRef::Primitive(_p) = inner.as_ref() {
632 if optional {
633 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as i32).collect())")
634 } else {
635 format!("{name}: val.{name}.iter().map(|&v| v as i32).collect()")
636 }
637 } else {
638 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
639 }
640 }
641 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
643 if optional {
644 format!("{name}: val.{name}.map(|v| v as f64)")
645 } else {
646 format!("{name}: val.{name} as f64")
647 }
648 }
649 TypeRef::Optional(inner)
651 if config.cast_large_ints_to_f64
652 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
653 {
654 format!("{name}: val.{name}.map(|v| v as f64)")
655 }
656 TypeRef::Vec(inner)
658 if config.cast_large_ints_to_f64
659 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
660 {
661 if optional {
662 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
663 } else {
664 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
665 }
666 }
667 TypeRef::Optional(inner)
669 if config.cast_large_ints_to_f64
670 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
671 {
672 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
673 }
674 TypeRef::Vec(outer)
676 if config.cast_large_ints_to_f64
677 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
678 {
679 if optional {
680 format!(
681 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
682 )
683 } else {
684 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
685 }
686 }
687 TypeRef::Optional(inner)
689 if config.cast_large_ints_to_f64
690 && 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)))) =>
691 {
692 format!(
693 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
694 )
695 }
696 TypeRef::Map(_k, v)
698 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
699 {
700 if optional {
701 format!("{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as f64)).collect())")
702 } else {
703 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as f64)).collect()")
704 }
705 }
706 TypeRef::Duration if config.cast_large_ints_to_f64 => {
708 if optional {
709 format!("{name}: val.{name}.map(|d| d.as_millis() as f64)")
710 } else {
711 format!("{name}: val.{name}.as_millis() as f64")
712 }
713 }
714 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
716 if optional {
717 format!("{name}: val.{name}.map(|v| v as f64)")
718 } else {
719 format!("{name}: val.{name} as f64")
720 }
721 }
722 TypeRef::Duration if config.cast_large_ints_to_i64 => {
724 if optional {
725 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
726 } else {
727 format!("{name}: val.{name}.as_millis() as u64 as i64")
728 }
729 }
730 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
732 let prefixed = format!("{prefix}{n}");
733 if optional {
734 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
735 } else {
736 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
737 }
738 }
739 TypeRef::Named(n) if is_enum_string(n) => {
741 if optional {
744 format!(
745 "{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())"
746 )
747 } else {
748 format!(
749 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
750 )
751 }
752 }
753 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
755 if optional {
756 format!(
757 "{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())"
758 )
759 } else {
760 format!(
761 "{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()"
762 )
763 }
764 }
765 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
767 {
768 format!(
769 "{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())"
770 )
771 }
772 TypeRef::Vec(inner)
774 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
775 {
776 if optional {
777 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
778 } else {
779 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
780 }
781 }
782 TypeRef::Optional(inner)
784 if config.cast_f32_to_f64
785 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
786 {
787 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
788 }
789 TypeRef::Optional(inner)
791 if config.cast_large_ints_to_i64
792 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
793 {
794 if let TypeRef::Vec(vi) = inner.as_ref() {
795 if let TypeRef::Primitive(p) = vi.as_ref() {
796 let cast_to = binding_prim_str(p);
797 if sanitized {
798 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
800 } else {
801 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
802 }
803 } else {
804 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
805 }
806 } else {
807 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
808 }
809 }
810 TypeRef::Vec(outer)
812 if config.cast_f32_to_f64
813 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
814 {
815 if optional {
816 format!(
817 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
818 )
819 } else {
820 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
821 }
822 }
823 TypeRef::Optional(inner)
825 if config.cast_f32_to_f64
826 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
827 {
828 format!(
829 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
830 )
831 }
832 TypeRef::Optional(inner)
834 if config.cast_large_ints_to_i64
835 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
836 {
837 if let TypeRef::Primitive(p) = inner.as_ref() {
838 let cast_to = binding_prim_str(p);
839 format!("{name}: val.{name}.map(|v| v as {cast_to})")
840 } else {
841 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
842 }
843 }
844 TypeRef::Map(_k, v)
846 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
847 {
848 if let TypeRef::Primitive(p) = v.as_ref() {
849 let cast_to = binding_prim_str(p);
850 if optional {
851 format!(
852 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
853 )
854 } else {
855 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
856 }
857 } else {
858 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
859 }
860 }
861 TypeRef::Vec(inner)
863 if config.cast_large_ints_to_i64
864 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
865 {
866 if let TypeRef::Primitive(p) = inner.as_ref() {
867 let cast_to = binding_prim_str(p);
868 if sanitized {
869 if optional {
871 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
872 } else {
873 format!("{name}: {{ let (a, b) = val.{name}; vec![a as {cast_to}, b as {cast_to}] }}")
874 }
875 } else if optional {
876 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
877 } else {
878 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
879 }
880 } else {
881 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
882 }
883 }
884 TypeRef::Vec(outer)
886 if config.cast_large_ints_to_i64
887 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
888 {
889 if let TypeRef::Vec(inner) = outer.as_ref() {
890 if let TypeRef::Primitive(p) = inner.as_ref() {
891 let cast_to = binding_prim_str(p);
892 if optional {
893 format!(
894 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
895 )
896 } else {
897 format!(
898 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
899 )
900 }
901 } else {
902 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
903 }
904 } else {
905 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
906 }
907 }
908 TypeRef::Json if config.json_to_string => {
910 if optional {
911 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
912 } else {
913 format!("{name}: val.{name}.to_string()")
914 }
915 }
916 TypeRef::Json if config.json_as_value => {
918 format!("{name}: val.{name}")
919 }
920 TypeRef::Optional(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
921 format!("{name}: val.{name}")
922 }
923 TypeRef::Vec(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
924 if optional {
925 format!("{name}: Some(val.{name})")
926 } else {
927 format!("{name}: val.{name}")
928 }
929 }
930 TypeRef::Map(_k, v) if config.json_as_value && matches!(v.as_ref(), TypeRef::Json) => {
931 if optional {
932 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
933 } else {
934 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v)).collect()")
935 }
936 }
937 TypeRef::Json if config.map_uses_jsvalue => {
939 if optional {
940 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
941 } else {
942 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
943 }
944 }
945 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
947 if optional {
948 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
949 } else {
950 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
951 }
952 }
953 TypeRef::Optional(inner)
955 if config.map_uses_jsvalue
956 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
957 {
958 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
959 }
960 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
962 }
963}
964
965fn apply_core_wrapper_from_core(
968 conversion: &str,
969 name: &str,
970 core_wrapper: &CoreWrapper,
971 vec_inner_core_wrapper: &CoreWrapper,
972 optional: bool,
973) -> String {
974 if *vec_inner_core_wrapper == CoreWrapper::Arc {
976 return conversion
977 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
978 .replace(
979 "map(|v| v.into_iter().map(Into::into)",
980 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
981 );
982 }
983
984 match core_wrapper {
985 CoreWrapper::None => conversion.to_string(),
986 CoreWrapper::Cow => {
987 let prefix = format!("{name}: ");
994 let already_some_wrapped = conversion
995 .strip_prefix(&prefix)
996 .is_some_and(|expr| expr.starts_with("Some("));
997 if optional {
998 format!("{name}: val.{name}.as_ref().map(|v| v.to_string())")
999 } else if already_some_wrapped {
1000 format!("{name}: Some(val.{name}.to_string())")
1001 } else {
1002 format!("{name}: val.{name}.to_string()")
1003 }
1004 }
1005 CoreWrapper::Arc => {
1006 if conversion.contains("{ inner: Arc::new(") {
1015 return conversion.replace("{ inner: Arc::new(v) }", "{ inner: v }").replace(
1016 &format!("{{ inner: Arc::new(val.{name}) }}"),
1017 &format!("{{ inner: val.{name} }}"),
1018 );
1019 }
1020 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1021 if optional {
1022 let simple_passthrough = format!("val.{name}");
1031 if expr == simple_passthrough {
1032 format!("{name}: {expr}.map(|v| (*v).clone().into())")
1033 } else {
1034 format!("{name}: {expr}")
1035 }
1036 } else {
1037 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
1038 format!("{name}: {unwrapped}")
1039 }
1040 } else {
1041 conversion.to_string()
1042 }
1043 }
1044 CoreWrapper::Bytes => {
1045 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1050 let already_converted_non_opt = expr == format!("val.{name}.to_vec().into()");
1051 let already_converted_opt = expr == format!("val.{name}.map(|v| v.to_vec().into())");
1052 if already_converted_non_opt || already_converted_opt {
1053 conversion.to_string()
1054 } else if optional {
1055 format!("{name}: {expr}.map(|v| v.to_vec().into())")
1056 } else if expr == format!("val.{name}") {
1057 format!("{name}: val.{name}.to_vec().into()")
1058 } else {
1059 conversion.to_string()
1060 }
1061 } else {
1062 conversion.to_string()
1063 }
1064 }
1065 CoreWrapper::ArcMutex => {
1066 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1068 if optional {
1069 format!("{name}: {expr}.map(|v| v.lock().unwrap().clone().into())")
1070 } else if expr == format!("val.{name}") {
1071 format!("{name}: val.{name}.lock().unwrap().clone().into()")
1072 } else {
1073 conversion.to_string()
1074 }
1075 } else {
1076 conversion.to_string()
1077 }
1078 }
1079 }
1080}