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 let binding_field = config.binding_field_name_owned(&typ.name, &field.name);
186 let conversion = if binding_field != field.name {
187 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
188 format!("{binding_field}: {expr}")
189 } else {
190 conversion
191 }
192 } else {
193 conversion
194 };
195 let field_is_trait_bridge = field.cfg.is_some() && config.never_skip_cfg_field_names.contains(&field.name) && {
201 let opaque_vec: Vec<String> = opaque_types.iter().cloned().collect();
202 crate::generators::structs::field_references_opaque_type(&field.ty, &opaque_vec)
203 };
204 let conversion = if field_is_trait_bridge {
205 format!("{}: Default::default()", binding_field)
206 } else {
207 conversion
208 };
209 fields.push(conversion);
210 }
211
212 crate::template_env::render(
213 "conversions/core_to_binding_impl",
214 minijinja::context! {
215 core_path => core_path,
216 binding_name => binding_name,
217 is_newtype => false,
218 newtype_inner_expr => "",
219 fields => fields,
220 },
221 )
222}
223
224pub fn field_conversion_from_core(
227 name: &str,
228 ty: &TypeRef,
229 optional: bool,
230 sanitized: bool,
231 opaque_types: &AHashSet<String>,
232) -> String {
233 if sanitized {
237 if let TypeRef::Vec(inner) = ty {
240 if matches!(inner.as_ref(), TypeRef::Primitive(_)) {
241 if optional {
242 return format!(
243 "{name}: val.{name}.map(|t| {{ let arr: Vec<_> = [t.0, t.1].into_iter().map(|v| v as _).collect(); arr }})"
244 );
245 }
246 return format!("{name}: vec![val.{name}.0 as _, val.{name}.1 as _]");
247 }
248 }
249 if let TypeRef::Optional(opt_inner) = ty {
251 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
252 if matches!(vec_inner.as_ref(), TypeRef::Primitive(_)) {
253 return format!("{name}: val.{name}.map(|t| vec![t.0 as _, t.1 as _])");
254 }
255 }
256 }
257 if let TypeRef::Map(k, v) = ty {
259 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
260 if optional {
261 return format!(
262 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
263 );
264 }
265 return format!(
266 "{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()"
267 );
268 }
269 }
270 if let TypeRef::Vec(inner) = ty {
273 if matches!(inner.as_ref(), TypeRef::String) {
274 if optional {
275 return format!(
276 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
277 );
278 }
279 return format!("{name}: val.{name}.iter().map(|i| format!(\"{{:?}}\", i)).collect()");
280 }
281 }
282 if let TypeRef::Optional(opt_inner) = ty {
284 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
285 if matches!(vec_inner.as_ref(), TypeRef::String) {
286 return format!(
287 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
288 );
289 }
290 }
291 }
292 if matches!(ty, TypeRef::String) {
297 if optional {
298 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
299 }
300 return format!("{name}: format!(\"{{:?}}\", val.{name})");
301 }
302 if optional {
305 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
306 }
307 return format!("{name}: format!(\"{{:?}}\", val.{name})");
308 }
309 match ty {
310 TypeRef::Duration => {
312 if optional {
313 return format!("{name}: val.{name}.map(|d| d.as_millis() as u64)");
314 }
315 format!("{name}: val.{name}.as_millis() as u64")
316 }
317 TypeRef::Path => {
319 if optional {
320 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
321 } else {
322 format!("{name}: val.{name}.to_string_lossy().to_string()")
323 }
324 }
325 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
326 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
327 }
328 TypeRef::Char => {
330 if optional {
331 format!("{name}: val.{name}.map(|c| c.to_string())")
332 } else {
333 format!("{name}: val.{name}.to_string()")
334 }
335 }
336 TypeRef::Bytes => {
340 if optional {
341 format!("{name}: val.{name}.map(|v| v.to_vec().into())")
342 } else {
343 format!("{name}: val.{name}.to_vec().into()")
344 }
345 }
346 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
348 if optional {
349 format!("{name}: val.{name}.map(|v| {n} {{ inner: Arc::new(v) }})")
350 } else {
351 format!("{name}: {n} {{ inner: Arc::new(val.{name}) }}")
352 }
353 }
354 TypeRef::Json => {
356 if optional {
357 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
358 } else {
359 format!("{name}: val.{name}.to_string()")
360 }
361 }
362 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
363 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
364 }
365 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
366 if optional {
367 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.to_string()).collect())")
368 } else {
369 format!("{name}: val.{name}.iter().map(ToString::to_string).collect()")
370 }
371 }
372 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Optional(oi) if matches!(oi.as_ref(), TypeRef::Json)) => {
374 if optional {
375 format!(
376 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.as_ref().map(ToString::to_string)).collect())"
377 )
378 } else {
379 format!("{name}: val.{name}.iter().map(|i| i.as_ref().map(ToString::to_string)).collect()")
380 }
381 }
382 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Json) => {
387 if optional {
388 format!(
389 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
390 )
391 } else {
392 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()")
393 }
394 }
395 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
397 if optional {
398 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect())")
399 } else {
400 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v)).collect()")
401 }
402 }
403 TypeRef::Map(k, v) if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) => {
407 if optional {
408 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())")
409 } else {
410 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
411 }
412 }
413 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Bytes) => {
416 if optional {
417 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect())")
418 } else {
419 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect()")
420 }
421 }
422 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_)) => {
424 if optional {
425 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
426 } else {
427 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.into())).collect()")
428 }
429 }
430 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_))) =>
432 {
433 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
434 }
435 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
437 if optional {
438 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
439 } else {
440 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
441 }
442 }
443 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_))) =>
445 {
446 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
447 }
448 _ => field_conversion_to_core(name, ty, optional),
450 }
451}
452
453pub fn field_conversion_from_core_cfg(
455 name: &str,
456 ty: &TypeRef,
457 optional: bool,
458 sanitized: bool,
459 opaque_types: &AHashSet<String>,
460 config: &ConversionConfig,
461) -> String {
462 if sanitized {
467 if config.map_uses_jsvalue {
468 if let TypeRef::Map(k, v) = ty {
471 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
472 if optional {
473 return format!(
474 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
475 );
476 }
477 return format!(
478 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
479 );
480 }
481 }
482 if let TypeRef::Vec(inner) = ty {
484 if matches!(inner.as_ref(), TypeRef::Json) {
485 if optional {
486 return format!(
487 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
488 );
489 }
490 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
491 }
492 }
493 }
494 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
495 }
496
497 if let Some(untagged_names) = config.untagged_data_enum_names {
500 let direct_named = matches!(ty, TypeRef::Named(n) if untagged_names.contains(n));
501 let optional_named = matches!(ty, TypeRef::Optional(inner)
502 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
503 let vec_named = matches!(ty, TypeRef::Vec(inner)
504 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
505 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
506 if matches!(outer.as_ref(), TypeRef::Vec(inner)
507 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n))));
508 if direct_named {
509 if optional {
510 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
511 }
512 return format!("{name}: serde_json::to_value(&val.{name}).unwrap_or(serde_json::Value::Null)");
513 }
514 if optional_named {
515 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_value(v).ok())");
516 }
517 if vec_named {
518 if optional {
519 return format!(
520 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
521 );
522 }
523 return format!("{name}: val.{name}.iter().filter_map(|x| serde_json::to_value(x).ok()).collect()");
524 }
525 if optional_vec_named {
526 return format!(
527 "{name}: val.{name}.as_ref().map(|v| v.iter().filter_map(|x| serde_json::to_value(x).ok()).collect())"
528 );
529 }
530 }
531
532 if config.vec_named_to_string {
536 if let TypeRef::Vec(inner) = ty {
537 if matches!(inner.as_ref(), TypeRef::Named(_)) {
538 if optional {
539 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok())");
540 }
541 return format!("{name}: serde_json::to_string(&val.{name}).unwrap_or_default()");
542 }
543 }
544 }
545
546 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
549 if optional {
550 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
551 }
552 return format!("{name}: format!(\"{{:?}}\", val.{name})");
553 }
554 if config.map_as_string {
555 if let TypeRef::Optional(inner) = ty {
556 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
557 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
558 }
559 }
560 }
561
562 if config.map_uses_jsvalue {
566 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
567 let is_map = matches!(ty, TypeRef::Map(_, _));
568 if is_map {
569 if optional {
570 return format!(
571 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
572 );
573 }
574 return format!(
575 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
576 );
577 }
578 if is_nested_vec {
579 if optional {
580 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
581 }
582 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
583 }
584 if let TypeRef::Optional(inner) = ty {
585 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
586 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
587 if is_inner_map {
588 return format!(
589 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
590 );
591 }
592 if is_inner_nested {
593 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
594 }
595 }
596 }
597
598 let prefix = config.type_name_prefix;
599 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
600
601 match ty {
602 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
604 let cast_to = binding_prim_str(p);
605 if optional {
606 format!("{name}: val.{name}.map(|v| v as {cast_to})")
607 } else {
608 format!("{name}: val.{name} as {cast_to}")
609 }
610 }
611 TypeRef::Optional(inner)
613 if config.cast_large_ints_to_i64
614 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
615 {
616 if let TypeRef::Primitive(p) = inner.as_ref() {
617 let cast_to = binding_prim_str(p);
618 format!("{name}: val.{name}.map(|v| v as {cast_to})")
619 } else {
620 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
621 }
622 }
623 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
625 if optional {
626 format!("{name}: val.{name}.map(|v| v as i32)")
627 } else {
628 format!("{name}: val.{name} as i32")
629 }
630 }
631 TypeRef::Optional(inner)
633 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
634 {
635 format!("{name}: val.{name}.map(|v| v as i32)")
636 }
637 TypeRef::Vec(inner)
639 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
640 {
641 if let TypeRef::Primitive(_p) = inner.as_ref() {
642 if optional {
643 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as i32).collect())")
644 } else {
645 format!("{name}: val.{name}.iter().map(|&v| v as i32).collect()")
646 }
647 } else {
648 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
649 }
650 }
651 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
653 if optional {
654 format!("{name}: val.{name}.map(|v| v as f64)")
655 } else {
656 format!("{name}: val.{name} as f64")
657 }
658 }
659 TypeRef::Optional(inner)
661 if config.cast_large_ints_to_f64
662 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
663 {
664 format!("{name}: val.{name}.map(|v| v as f64)")
665 }
666 TypeRef::Vec(inner)
668 if config.cast_large_ints_to_f64
669 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
670 {
671 if optional {
672 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
673 } else {
674 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
675 }
676 }
677 TypeRef::Optional(inner)
679 if config.cast_large_ints_to_f64
680 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
681 {
682 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
683 }
684 TypeRef::Vec(outer)
686 if config.cast_large_ints_to_f64
687 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
688 {
689 if optional {
690 format!(
691 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
692 )
693 } else {
694 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
695 }
696 }
697 TypeRef::Optional(inner)
699 if config.cast_large_ints_to_f64
700 && 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)))) =>
701 {
702 format!(
703 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
704 )
705 }
706 TypeRef::Map(_k, v)
708 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
709 {
710 if optional {
711 format!("{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as f64)).collect())")
712 } else {
713 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as f64)).collect()")
714 }
715 }
716 TypeRef::Duration if config.cast_large_ints_to_f64 => {
718 if optional {
719 format!("{name}: val.{name}.map(|d| d.as_millis() as f64)")
720 } else {
721 format!("{name}: val.{name}.as_millis() as f64")
722 }
723 }
724 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
726 if optional {
727 format!("{name}: val.{name}.map(|v| v as f64)")
728 } else {
729 format!("{name}: val.{name} as f64")
730 }
731 }
732 TypeRef::Duration if config.cast_large_ints_to_i64 => {
734 if optional {
735 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
736 } else {
737 format!("{name}: val.{name}.as_millis() as u64 as i64")
738 }
739 }
740 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
742 let prefixed = format!("{prefix}{n}");
743 if optional {
744 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
745 } else {
746 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
747 }
748 }
749 TypeRef::Named(n) if is_enum_string(n) => {
751 if optional {
754 format!(
755 "{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())"
756 )
757 } else {
758 format!(
759 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
760 )
761 }
762 }
763 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
765 if optional {
766 format!(
767 "{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())"
768 )
769 } else {
770 format!(
771 "{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()"
772 )
773 }
774 }
775 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
777 {
778 format!(
779 "{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())"
780 )
781 }
782 TypeRef::Vec(inner)
784 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
785 {
786 if optional {
787 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
788 } else {
789 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
790 }
791 }
792 TypeRef::Optional(inner)
794 if config.cast_f32_to_f64
795 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
796 {
797 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
798 }
799 TypeRef::Optional(inner)
801 if config.cast_large_ints_to_i64
802 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
803 {
804 if let TypeRef::Vec(vi) = inner.as_ref() {
805 if let TypeRef::Primitive(p) = vi.as_ref() {
806 let cast_to = binding_prim_str(p);
807 if sanitized {
808 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
810 } else {
811 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
812 }
813 } else {
814 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
815 }
816 } else {
817 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
818 }
819 }
820 TypeRef::Vec(outer)
822 if config.cast_f32_to_f64
823 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
824 {
825 if optional {
826 format!(
827 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
828 )
829 } else {
830 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
831 }
832 }
833 TypeRef::Optional(inner)
835 if config.cast_f32_to_f64
836 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
837 {
838 format!(
839 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
840 )
841 }
842 TypeRef::Optional(inner)
844 if config.cast_large_ints_to_i64
845 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
846 {
847 if let TypeRef::Primitive(p) = inner.as_ref() {
848 let cast_to = binding_prim_str(p);
849 format!("{name}: val.{name}.map(|v| v as {cast_to})")
850 } else {
851 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
852 }
853 }
854 TypeRef::Map(_k, v)
856 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
857 {
858 if let TypeRef::Primitive(p) = v.as_ref() {
859 let cast_to = binding_prim_str(p);
860 if optional {
861 format!(
862 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
863 )
864 } else {
865 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
866 }
867 } else {
868 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
869 }
870 }
871 TypeRef::Vec(inner)
873 if config.cast_large_ints_to_i64
874 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
875 {
876 if let TypeRef::Primitive(p) = inner.as_ref() {
877 let cast_to = binding_prim_str(p);
878 if sanitized {
879 if optional {
881 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
882 } else {
883 format!("{name}: {{ let (a, b) = val.{name}; vec![a as {cast_to}, b as {cast_to}] }}")
884 }
885 } else if optional {
886 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
887 } else {
888 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
889 }
890 } else {
891 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
892 }
893 }
894 TypeRef::Vec(outer)
896 if config.cast_large_ints_to_i64
897 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
898 {
899 if let TypeRef::Vec(inner) = outer.as_ref() {
900 if let TypeRef::Primitive(p) = inner.as_ref() {
901 let cast_to = binding_prim_str(p);
902 if optional {
903 format!(
904 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
905 )
906 } else {
907 format!(
908 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
909 )
910 }
911 } else {
912 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
913 }
914 } else {
915 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
916 }
917 }
918 TypeRef::Json if config.json_to_string => {
920 if optional {
921 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
922 } else {
923 format!("{name}: val.{name}.to_string()")
924 }
925 }
926 TypeRef::Json if config.json_as_value => {
928 format!("{name}: val.{name}")
929 }
930 TypeRef::Optional(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
931 format!("{name}: val.{name}")
932 }
933 TypeRef::Vec(inner) if config.json_as_value && matches!(inner.as_ref(), TypeRef::Json) => {
934 if optional {
935 format!("{name}: Some(val.{name})")
936 } else {
937 format!("{name}: val.{name}")
938 }
939 }
940 TypeRef::Map(_k, v) if config.json_as_value && matches!(v.as_ref(), TypeRef::Json) => {
941 if optional {
942 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
943 } else {
944 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v)).collect()")
945 }
946 }
947 TypeRef::Json if config.map_uses_jsvalue => {
949 if optional {
950 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
951 } else {
952 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
953 }
954 }
955 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
957 if optional {
958 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
959 } else {
960 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
961 }
962 }
963 TypeRef::Optional(inner)
965 if config.map_uses_jsvalue
966 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
967 {
968 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
969 }
970 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
972 }
973}
974
975fn apply_core_wrapper_from_core(
978 conversion: &str,
979 name: &str,
980 core_wrapper: &CoreWrapper,
981 vec_inner_core_wrapper: &CoreWrapper,
982 optional: bool,
983) -> String {
984 if *vec_inner_core_wrapper == CoreWrapper::Arc {
986 return conversion
987 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
988 .replace(
989 "map(|v| v.into_iter().map(Into::into)",
990 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
991 );
992 }
993
994 match core_wrapper {
995 CoreWrapper::None => conversion.to_string(),
996 CoreWrapper::Cow => {
997 let prefix = format!("{name}: ");
1004 let already_some_wrapped = conversion
1005 .strip_prefix(&prefix)
1006 .is_some_and(|expr| expr.starts_with("Some("));
1007 if optional {
1008 format!("{name}: val.{name}.as_ref().map(|v| v.to_string())")
1009 } else if already_some_wrapped {
1010 format!("{name}: Some(val.{name}.to_string())")
1011 } else {
1012 format!("{name}: val.{name}.to_string()")
1013 }
1014 }
1015 CoreWrapper::Arc => {
1016 if conversion.contains("{ inner: Arc::new(") {
1025 return conversion.replace("{ inner: Arc::new(v) }", "{ inner: v }").replace(
1026 &format!("{{ inner: Arc::new(val.{name}) }}"),
1027 &format!("{{ inner: val.{name} }}"),
1028 );
1029 }
1030 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1031 if optional {
1032 let simple_passthrough = format!("val.{name}");
1041 if expr == simple_passthrough {
1042 format!("{name}: {expr}.map(|v| (*v).clone().into())")
1043 } else {
1044 format!("{name}: {expr}")
1045 }
1046 } else {
1047 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
1048 format!("{name}: {unwrapped}")
1049 }
1050 } else {
1051 conversion.to_string()
1052 }
1053 }
1054 CoreWrapper::Bytes => {
1055 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1060 let already_converted_non_opt = expr == format!("val.{name}.to_vec().into()");
1061 let already_converted_opt = expr == format!("val.{name}.map(|v| v.to_vec().into())");
1062 if already_converted_non_opt || already_converted_opt {
1063 conversion.to_string()
1064 } else if optional {
1065 format!("{name}: {expr}.map(|v| v.to_vec().into())")
1066 } else if expr == format!("val.{name}") {
1067 format!("{name}: val.{name}.to_vec().into()")
1068 } else {
1069 conversion.to_string()
1070 }
1071 } else {
1072 conversion.to_string()
1073 }
1074 }
1075 CoreWrapper::ArcMutex => {
1076 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1078 if optional {
1079 format!("{name}: {expr}.map(|v| v.lock().unwrap().clone().into())")
1080 } else if expr == format!("val.{name}") {
1081 format!("{name}: val.{name}.lock().unwrap().clone().into()")
1082 } else {
1083 conversion.to_string()
1084 }
1085 } else {
1086 conversion.to_string()
1087 }
1088 }
1089 }
1090}