1use ahash::AHashSet;
2use alef_core::ir::{CoreWrapper, PrimitiveType, TypeDef, TypeRef};
3
4use super::ConversionConfig;
5use super::binding_to_core::field_conversion_to_core;
6use super::helpers::is_newtype;
7use super::helpers::{binding_prim_str, core_type_path_remapped, needs_f64_cast, needs_i32_cast, needs_i64_cast};
8
9pub fn gen_from_core_to_binding(typ: &TypeDef, core_import: &str, opaque_types: &AHashSet<String>) -> String {
11 gen_from_core_to_binding_cfg(typ, core_import, opaque_types, &ConversionConfig::default())
12}
13
14pub fn gen_from_core_to_binding_cfg(
16 typ: &TypeDef,
17 core_import: &str,
18 opaque_types: &AHashSet<String>,
19 config: &ConversionConfig,
20) -> String {
21 let core_path = core_type_path_remapped(typ, core_import, config.source_crate_remaps);
22 let binding_name = format!("{}{}", config.type_name_prefix, typ.name);
23
24 if is_newtype(typ) {
26 let field = &typ.fields[0];
27 let newtype_inner_expr = match &field.ty {
28 TypeRef::Named(_) => "val.0.into()".to_string(),
29 TypeRef::Path => "val.0.to_string_lossy().to_string()".to_string(),
30 TypeRef::Duration => "val.0.as_millis() as u64".to_string(),
31 _ => "val.0".to_string(),
32 };
33 return crate::template_env::render(
34 "conversions/core_to_binding_impl",
35 minijinja::context! {
36 core_path => core_path,
37 binding_name => binding_name,
38 is_newtype => true,
39 newtype_inner_expr => newtype_inner_expr,
40 fields => vec![] as Vec<String>,
41 },
42 );
43 }
44
45 let optionalized = config.optionalize_defaults && typ.has_default;
46
47 let mut fields = Vec::new();
49 for field in &typ.fields {
50 if !config.exclude_types.is_empty()
52 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types)
53 {
54 continue;
55 }
56 if field.cfg.is_some()
61 && !config.never_skip_cfg_field_names.contains(&field.name)
62 && config.strip_cfg_fields_from_binding_struct
63 {
64 continue;
65 }
66 let base_conversion = field_conversion_from_core_cfg(
67 &field.name,
68 &field.ty,
69 field.optional,
70 field.sanitized,
71 opaque_types,
72 config,
73 );
74 let base_conversion = if field.is_boxed && matches!(&field.ty, TypeRef::Named(_)) {
76 if field.optional {
77 let src = format!("{}: val.{}.map(Into::into)", field.name, field.name);
79 let dst = format!("{}: val.{}.map(|v| (*v).into())", field.name, field.name);
80 if base_conversion == src { dst } else { base_conversion }
81 } else {
82 base_conversion.replace(&format!("val.{}", field.name), &format!("(*val.{})", field.name))
84 }
85 } else {
86 base_conversion
87 };
88 let base_conversion = if field.newtype_wrapper.is_some() {
94 match &field.ty {
95 TypeRef::Optional(_) => {
96 base_conversion.replace(
98 &format!("val.{}", field.name),
99 &format!("val.{}.map(|v| v.0)", field.name),
100 )
101 }
102 TypeRef::Vec(_) => {
103 base_conversion.replace(
105 &format!("val.{}", field.name),
106 &format!("val.{}.iter().map(|v| v.0).collect::<Vec<_>>()", field.name),
107 )
108 }
109 _ if field.optional => base_conversion.replace(
112 &format!("val.{}", field.name),
113 &format!("val.{}.map(|v| v.0)", field.name),
114 ),
115 _ => {
116 base_conversion.replace(&format!("val.{}", field.name), &format!("val.{}.0", field.name))
118 }
119 }
120 } else {
121 base_conversion
122 };
123 let is_flattened_optional = field.optional && matches!(field.ty, TypeRef::Optional(_));
129 let base_conversion = if is_flattened_optional {
130 if let TypeRef::Optional(inner) = &field.ty {
131 let inner_conv = field_conversion_from_core_cfg(
133 &field.name,
134 inner.as_ref(),
135 true,
136 field.sanitized,
137 opaque_types,
138 config,
139 );
140 inner_conv.replace(&format!("val.{}", field.name), &format!("val.{}.flatten()", field.name))
142 } else {
143 base_conversion
144 }
145 } else {
146 base_conversion
147 };
148 let needs_some_wrap = !is_flattened_optional
152 && ((optionalized && !field.optional)
153 || (config.option_duration_on_defaults
154 && typ.has_default
155 && !field.optional
156 && matches!(field.ty, TypeRef::Duration)));
157 let conversion = if needs_some_wrap {
158 if let Some(expr) = base_conversion.strip_prefix(&format!("{}: ", field.name)) {
160 format!("{}: Some({})", field.name, expr)
161 } else {
162 base_conversion
163 }
164 } else {
165 base_conversion
166 };
167 let is_opaque_no_wrapper_field = field.core_wrapper == CoreWrapper::None
171 && matches!(&field.ty, TypeRef::Named(n) if config
172 .opaque_types
173 .is_some_and(|opaque| opaque.contains(n.as_str())));
174 let conversion = if is_opaque_no_wrapper_field {
180 if config.trait_bridge_field_is_arc_wrapper(&field.name) {
186 if let TypeRef::Named(name) = &field.ty {
187 let wrapper = format!("{}{}", config.type_name_prefix, name);
188 if field.optional {
189 format!(
190 "{}: val.{}.map(|v| {wrapper} {{ inner: std::sync::Arc::new(v) }})",
191 field.name, field.name
192 )
193 } else {
194 format!(
195 "{}: {wrapper} {{ inner: std::sync::Arc::new(val.{}) }}",
196 field.name, field.name
197 )
198 }
199 } else {
200 format!("{}: Default::default()", field.name)
201 }
202 } else {
203 format!("{}: Default::default()", field.name)
204 }
205 } else if !field.sanitized || field.core_wrapper == alef_core::ir::CoreWrapper::Cow {
206 apply_core_wrapper_from_core(
207 &conversion,
208 &field.name,
209 &field.core_wrapper,
210 &field.vec_inner_core_wrapper,
211 field.optional,
212 )
213 } else {
214 conversion
215 };
216 let binding_field = config.binding_field_name_owned(&typ.name, &field.name);
220 let conversion = if binding_field != field.name {
221 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
222 format!("{binding_field}: {expr}")
223 } else {
224 conversion
225 }
226 } else {
227 conversion
228 };
229 fields.push(conversion);
230 }
231
232 crate::template_env::render(
233 "conversions/core_to_binding_impl",
234 minijinja::context! {
235 core_path => core_path,
236 binding_name => binding_name,
237 is_newtype => false,
238 newtype_inner_expr => "",
239 fields => fields,
240 },
241 )
242}
243
244pub fn field_conversion_from_core(
247 name: &str,
248 ty: &TypeRef,
249 optional: bool,
250 sanitized: bool,
251 opaque_types: &AHashSet<String>,
252) -> String {
253 if sanitized {
257 if let TypeRef::Vec(inner) = ty {
260 if matches!(inner.as_ref(), TypeRef::Primitive(_)) {
261 if optional {
262 return format!(
263 "{name}: val.{name}.map(|t| {{ let arr: Vec<_> = [t.0, t.1].into_iter().map(|v| v as _).collect(); arr }})"
264 );
265 }
266 return format!("{name}: vec![val.{name}.0 as _, val.{name}.1 as _]");
267 }
268 }
269 if let TypeRef::Optional(opt_inner) = ty {
271 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
272 if matches!(vec_inner.as_ref(), TypeRef::Primitive(_)) {
273 return format!("{name}: val.{name}.map(|t| vec![t.0 as _, t.1 as _])");
274 }
275 }
276 }
277 if let TypeRef::Map(k, v) = ty {
279 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
280 if optional {
281 return format!(
282 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
283 );
284 }
285 return format!(
286 "{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()"
287 );
288 }
289 }
290 if let TypeRef::Vec(inner) = ty {
293 if matches!(inner.as_ref(), TypeRef::String) {
294 if optional {
295 return format!(
296 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
297 );
298 }
299 return format!("{name}: val.{name}.iter().map(|i| format!(\"{{:?}}\", i)).collect()");
300 }
301 }
302 if let TypeRef::Optional(opt_inner) = ty {
304 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
305 if matches!(vec_inner.as_ref(), TypeRef::String) {
306 return format!(
307 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
308 );
309 }
310 }
311 }
312 if matches!(ty, TypeRef::String) {
317 if optional {
318 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
319 }
320 return format!("{name}: format!(\"{{:?}}\", val.{name})");
321 }
322 if optional {
325 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
326 }
327 return format!("{name}: format!(\"{{:?}}\", val.{name})");
328 }
329 match ty {
330 TypeRef::Duration => {
332 if optional {
333 return format!("{name}: val.{name}.map(|d| d.as_millis() as u64)");
334 }
335 format!("{name}: val.{name}.as_millis() as u64")
336 }
337 TypeRef::Path => {
339 if optional {
340 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
341 } else {
342 format!("{name}: val.{name}.to_string_lossy().to_string()")
343 }
344 }
345 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
346 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
347 }
348 TypeRef::Char => {
350 if optional {
351 format!("{name}: val.{name}.map(|c| c.to_string())")
352 } else {
353 format!("{name}: val.{name}.to_string()")
354 }
355 }
356 TypeRef::Bytes => {
360 if optional {
361 format!("{name}: val.{name}.map(|v| v.to_vec().into())")
362 } else {
363 format!("{name}: val.{name}.to_vec().into()")
364 }
365 }
366 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
368 if optional {
369 format!("{name}: val.{name}.map(|v| {n} {{ inner: Arc::new(v) }})")
370 } else {
371 format!("{name}: {n} {{ inner: Arc::new(val.{name}) }}")
372 }
373 }
374 TypeRef::Json => {
376 if optional {
377 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
378 } else {
379 format!("{name}: val.{name}.to_string()")
380 }
381 }
382 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
383 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
384 }
385 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
386 if optional {
387 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.to_string()).collect())")
388 } else {
389 format!("{name}: val.{name}.iter().map(ToString::to_string).collect()")
390 }
391 }
392 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Optional(oi) if matches!(oi.as_ref(), TypeRef::Json)) => {
394 if optional {
395 format!(
396 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.as_ref().map(ToString::to_string)).collect())"
397 )
398 } else {
399 format!("{name}: val.{name}.iter().map(|i| i.as_ref().map(ToString::to_string)).collect()")
400 }
401 }
402 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Json) => {
407 if optional {
408 format!(
409 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
410 )
411 } else {
412 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()")
413 }
414 }
415 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
417 if optional {
418 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect())")
419 } else {
420 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v)).collect()")
421 }
422 }
423 TypeRef::Map(k, v) if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) => {
427 if optional {
428 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())")
429 } else {
430 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
431 }
432 }
433 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Bytes) => {
436 if optional {
437 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect())")
438 } else {
439 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect()")
440 }
441 }
442 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_)) => {
444 if optional {
445 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
446 } else {
447 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.into())).collect()")
448 }
449 }
450 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_))) =>
452 {
453 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
454 }
455 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
457 if optional {
458 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
459 } else {
460 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
461 }
462 }
463 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_))) =>
465 {
466 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
467 }
468 _ => field_conversion_to_core(name, ty, optional),
470 }
471}
472
473pub fn field_conversion_from_core_cfg(
475 name: &str,
476 ty: &TypeRef,
477 optional: bool,
478 sanitized: bool,
479 opaque_types: &AHashSet<String>,
480 config: &ConversionConfig,
481) -> String {
482 if sanitized {
487 if config.map_uses_jsvalue {
488 if let TypeRef::Map(k, v) = ty {
491 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
492 if optional {
493 return format!(
494 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
495 );
496 }
497 return format!(
498 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
499 );
500 }
501 }
502 if let TypeRef::Vec(inner) = ty {
504 if matches!(inner.as_ref(), TypeRef::Json) {
505 if optional {
506 return format!(
507 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
508 );
509 }
510 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
511 }
512 }
513 }
514 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
515 }
516
517 if let Some(untagged_names) = config.untagged_data_enum_names {
520 let direct_named = matches!(ty, TypeRef::Named(n) if untagged_names.contains(n));
521 let optional_named = matches!(ty, TypeRef::Optional(inner)
522 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
523 let vec_named = matches!(ty, TypeRef::Vec(inner)
524 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
525 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
526 if matches!(outer.as_ref(), TypeRef::Vec(inner)
527 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n))));
528 if direct_named {
529 if optional {
530 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
531 }
532 return format!("{name}: serde_json::to_value(&val.{name}).unwrap_or(serde_json::Value::Null)");
533 }
534 if optional_named {
535 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
536 }
537 if vec_named {
538 if optional {
539 return format!(
540 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
541 );
542 }
543 return format!("{name}: val.{name}.iter().filter_map(|x| serde_json::to_value(x).ok()).collect()");
544 }
545 if optional_vec_named {
546 return format!(
547 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
548 );
549 }
550 }
551
552 if config.vec_named_to_string {
556 if let TypeRef::Vec(inner) = ty {
557 if matches!(inner.as_ref(), TypeRef::Named(_)) {
558 if optional {
559 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok())");
560 }
561 return format!("{name}: serde_json::to_string(&val.{name}).unwrap_or_default()");
562 }
563 }
564 }
565
566 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
569 if optional {
570 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
571 }
572 return format!("{name}: format!(\"{{:?}}\", val.{name})");
573 }
574 if config.map_as_string {
575 if let TypeRef::Optional(inner) = ty {
576 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
577 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
578 }
579 }
580 }
581
582 if config.map_uses_jsvalue {
586 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
587 let is_map = matches!(ty, TypeRef::Map(_, _));
588 if is_map {
589 if optional {
590 return format!(
591 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
592 );
593 }
594 return format!(
595 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
596 );
597 }
598 if is_nested_vec {
599 if optional {
600 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
601 }
602 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
603 }
604 if let TypeRef::Optional(inner) = ty {
605 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
606 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
607 if is_inner_map {
608 return format!(
609 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
610 );
611 }
612 if is_inner_nested {
613 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
614 }
615 }
616 }
617
618 let prefix = config.type_name_prefix;
619 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
620
621 match ty {
622 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
624 let cast_to = binding_prim_str(p);
625 if optional {
626 format!("{name}: val.{name}.map(|v| v as {cast_to})")
627 } else {
628 format!("{name}: val.{name} as {cast_to}")
629 }
630 }
631 TypeRef::Optional(inner)
633 if config.cast_large_ints_to_i64
634 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
635 {
636 if let TypeRef::Primitive(p) = inner.as_ref() {
637 let cast_to = binding_prim_str(p);
638 format!("{name}: val.{name}.map(|v| v as {cast_to})")
639 } else {
640 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
641 }
642 }
643 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
645 if optional {
646 format!("{name}: val.{name}.map(|v| v as i32)")
647 } else {
648 format!("{name}: val.{name} as i32")
649 }
650 }
651 TypeRef::Optional(inner)
653 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
654 {
655 format!("{name}: val.{name}.map(|v| v as i32)")
656 }
657 TypeRef::Vec(inner)
659 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
660 {
661 if let TypeRef::Primitive(_p) = inner.as_ref() {
662 if optional {
663 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as i32).collect())")
664 } else {
665 format!("{name}: val.{name}.iter().map(|&v| v as i32).collect()")
666 }
667 } else {
668 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
669 }
670 }
671 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
673 if optional {
674 format!("{name}: val.{name}.map(|v| v as f64)")
675 } else {
676 format!("{name}: val.{name} as f64")
677 }
678 }
679 TypeRef::Optional(inner)
681 if config.cast_large_ints_to_f64
682 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
683 {
684 format!("{name}: val.{name}.map(|v| v as f64)")
685 }
686 TypeRef::Vec(inner)
688 if config.cast_large_ints_to_f64
689 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
690 {
691 if optional {
692 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
693 } else {
694 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
695 }
696 }
697 TypeRef::Optional(inner)
699 if config.cast_large_ints_to_f64
700 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
701 {
702 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
703 }
704 TypeRef::Vec(outer)
706 if config.cast_large_ints_to_f64
707 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
708 {
709 if optional {
710 format!(
711 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
712 )
713 } else {
714 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
715 }
716 }
717 TypeRef::Optional(inner)
719 if config.cast_large_ints_to_f64
720 && 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)))) =>
721 {
722 format!(
723 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
724 )
725 }
726 TypeRef::Map(_k, v)
728 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
729 {
730 if optional {
731 format!("{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as f64)).collect())")
732 } else {
733 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as f64)).collect()")
734 }
735 }
736 TypeRef::Duration if config.cast_large_ints_to_f64 => {
738 if optional {
739 format!("{name}: val.{name}.map(|d| d.as_millis() as f64)")
740 } else {
741 format!("{name}: val.{name}.as_millis() as f64")
742 }
743 }
744 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
746 if optional {
747 format!("{name}: val.{name}.map(|v| v as f64)")
748 } else {
749 format!("{name}: val.{name} as f64")
750 }
751 }
752 TypeRef::Duration if config.cast_large_ints_to_i64 => {
754 if optional {
755 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
756 } else {
757 format!("{name}: val.{name}.as_millis() as u64 as i64")
758 }
759 }
760 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
762 let prefixed = format!("{prefix}{n}");
763 if optional {
764 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
765 } else {
766 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
767 }
768 }
769 TypeRef::Named(n) if is_enum_string(n) => {
771 if optional {
774 format!(
775 "{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())"
776 )
777 } else {
778 format!(
779 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
780 )
781 }
782 }
783 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
785 if optional {
786 format!(
787 "{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())"
788 )
789 } else {
790 format!(
791 "{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()"
792 )
793 }
794 }
795 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
797 {
798 format!(
799 "{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())"
800 )
801 }
802 TypeRef::Vec(inner)
804 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
805 {
806 if optional {
807 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
808 } else {
809 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
810 }
811 }
812 TypeRef::Optional(inner)
814 if config.cast_f32_to_f64
815 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
816 {
817 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
818 }
819 TypeRef::Optional(inner)
821 if config.cast_large_ints_to_i64
822 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
823 {
824 if let TypeRef::Vec(vi) = inner.as_ref() {
825 if let TypeRef::Primitive(p) = vi.as_ref() {
826 let cast_to = binding_prim_str(p);
827 if sanitized {
828 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
830 } else {
831 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
832 }
833 } else {
834 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
835 }
836 } else {
837 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
838 }
839 }
840 TypeRef::Vec(outer)
842 if config.cast_f32_to_f64
843 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
844 {
845 if optional {
846 format!(
847 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
848 )
849 } else {
850 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
851 }
852 }
853 TypeRef::Optional(inner)
855 if config.cast_f32_to_f64
856 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
857 {
858 format!(
859 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
860 )
861 }
862 TypeRef::Optional(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 format!("{name}: val.{name}.map(|v| v as {cast_to})")
870 } else {
871 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
872 }
873 }
874 TypeRef::Map(_k, v)
876 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
877 {
878 if let TypeRef::Primitive(p) = v.as_ref() {
879 let cast_to = binding_prim_str(p);
880 if optional {
881 format!(
882 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
883 )
884 } else {
885 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
886 }
887 } else {
888 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
889 }
890 }
891 TypeRef::Vec(inner)
893 if config.cast_large_ints_to_i64
894 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
895 {
896 if let TypeRef::Primitive(p) = inner.as_ref() {
897 let cast_to = binding_prim_str(p);
898 if sanitized {
899 if optional {
901 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
902 } else {
903 format!("{name}: {{ let (a, b) = val.{name}; vec![a as {cast_to}, b as {cast_to}] }}")
904 }
905 } else if optional {
906 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
907 } else {
908 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
909 }
910 } else {
911 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
912 }
913 }
914 TypeRef::Vec(outer)
916 if config.cast_large_ints_to_i64
917 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
918 {
919 if let TypeRef::Vec(inner) = outer.as_ref() {
920 if let TypeRef::Primitive(p) = inner.as_ref() {
921 let cast_to = binding_prim_str(p);
922 if optional {
923 format!(
924 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
925 )
926 } else {
927 format!(
928 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
929 )
930 }
931 } else {
932 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
933 }
934 } else {
935 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
936 }
937 }
938 TypeRef::Json if config.json_to_string => {
940 if optional {
941 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
942 } else {
943 format!("{name}: val.{name}.to_string()")
944 }
945 }
946 TypeRef::Json if config.json_as_value => {
948 format!("{name}: val.{name}")
949 }
950 TypeRef::Optional(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
951 format!("{name}: val.{name}")
952 }
953 TypeRef::Vec(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
954 if optional {
955 format!("{name}: Some(val.{name})")
956 } else {
957 format!("{name}: val.{name}")
958 }
959 }
960 TypeRef::Map(_k, v) if config.json_as_value && matches!(v.as_ref(), TypeRef::Json) => {
961 if optional {
962 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
963 } else {
964 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v)).collect()")
965 }
966 }
967 TypeRef::Json if config.map_uses_jsvalue => {
969 if optional {
970 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
971 } else {
972 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
973 }
974 }
975 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
977 if optional {
978 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
979 } else {
980 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
981 }
982 }
983 TypeRef::Optional(inner)
985 if config.map_uses_jsvalue
986 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
987 {
988 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
989 }
990 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
992 }
993}
994
995fn apply_core_wrapper_from_core(
998 conversion: &str,
999 name: &str,
1000 core_wrapper: &CoreWrapper,
1001 vec_inner_core_wrapper: &CoreWrapper,
1002 optional: bool,
1003) -> String {
1004 if *vec_inner_core_wrapper == CoreWrapper::Arc {
1006 return conversion
1007 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
1008 .replace(
1009 "map(|v| v.into_iter().map(Into::into)",
1010 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
1011 );
1012 }
1013
1014 match core_wrapper {
1015 CoreWrapper::None => conversion.to_string(),
1016 CoreWrapper::Cow => {
1017 let prefix = format!("{name}: ");
1024 let already_some_wrapped = conversion
1025 .strip_prefix(&prefix)
1026 .is_some_and(|expr| expr.starts_with("Some("));
1027 if optional {
1028 format!("{name}: val.{name}.as_ref().map(|v| v.to_string())")
1029 } else if already_some_wrapped {
1030 format!("{name}: Some(val.{name}.to_string())")
1031 } else {
1032 format!("{name}: val.{name}.to_string()")
1033 }
1034 }
1035 CoreWrapper::Arc => {
1036 if conversion.contains("{ inner: Arc::new(") {
1045 return conversion.replace("{ inner: Arc::new(v) }", "{ inner: v }").replace(
1046 &format!("{{ inner: Arc::new(val.{name}) }}"),
1047 &format!("{{ inner: val.{name} }}"),
1048 );
1049 }
1050 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1051 if optional {
1052 let simple_passthrough = format!("val.{name}");
1061 if expr == simple_passthrough {
1062 format!("{name}: {expr}.map(|v| (*v).clone().into())")
1063 } else {
1064 format!("{name}: {expr}")
1065 }
1066 } else {
1067 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
1068 format!("{name}: {unwrapped}")
1069 }
1070 } else {
1071 conversion.to_string()
1072 }
1073 }
1074 CoreWrapper::Bytes => {
1075 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1080 let already_converted_non_opt = expr == format!("val.{name}.to_vec().into()");
1081 let already_converted_opt = expr == format!("val.{name}.map(|v| v.to_vec().into())");
1082 if already_converted_non_opt || already_converted_opt {
1083 conversion.to_string()
1084 } else if optional {
1085 format!("{name}: {expr}.map(|v| v.to_vec().into())")
1086 } else if expr == format!("val.{name}") {
1087 format!("{name}: val.{name}.to_vec().into()")
1088 } else {
1089 conversion.to_string()
1090 }
1091 } else {
1092 conversion.to_string()
1093 }
1094 }
1095 CoreWrapper::ArcMutex => {
1096 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1098 if optional {
1099 format!("{name}: {expr}.map(|v| v.lock().unwrap().clone().into())")
1100 } else if expr == format!("val.{name}") {
1101 format!("{name}: val.{name}.lock().unwrap().clone().into()")
1102 } else {
1103 conversion.to_string()
1104 }
1105 } else {
1106 conversion.to_string()
1107 }
1108 }
1109 }
1110}