1use ahash::AHashSet;
2use alef_core::ir::{CoreWrapper, PrimitiveType, TypeDef, TypeRef};
3use std::fmt::Write;
4
5use super::ConversionConfig;
6use super::binding_to_core::field_conversion_to_core;
7use super::helpers::is_newtype;
8use super::helpers::{binding_prim_str, core_type_path_remapped, needs_f64_cast, needs_i32_cast, needs_i64_cast};
9
10pub fn gen_from_core_to_binding(typ: &TypeDef, core_import: &str, opaque_types: &AHashSet<String>) -> String {
12 gen_from_core_to_binding_cfg(typ, core_import, opaque_types, &ConversionConfig::default())
13}
14
15pub fn gen_from_core_to_binding_cfg(
17 typ: &TypeDef,
18 core_import: &str,
19 opaque_types: &AHashSet<String>,
20 config: &ConversionConfig,
21) -> String {
22 let core_path = core_type_path_remapped(typ, core_import, config.source_crate_remaps);
23 let binding_name = format!("{}{}", config.type_name_prefix, typ.name);
24 let mut out = String::with_capacity(256);
25 writeln!(out, "#[allow(clippy::redundant_closure, clippy::useless_conversion)]").ok();
26 writeln!(out, "impl From<{core_path}> for {binding_name} {{").ok();
27 writeln!(out, " fn from(val: {core_path}) -> Self {{").ok();
28
29 if is_newtype(typ) {
31 let field = &typ.fields[0];
32 let inner_expr = match &field.ty {
33 TypeRef::Named(_) => "val.0.into()".to_string(),
34 TypeRef::Path => "val.0.to_string_lossy().to_string()".to_string(),
35 TypeRef::Duration => "val.0.as_millis() as u64".to_string(),
36 _ => "val.0".to_string(),
37 };
38 writeln!(out, " Self {{ _0: {inner_expr} }}").ok();
39 writeln!(out, " }}").ok();
40 write!(out, "}}").ok();
41 return out;
42 }
43
44 let optionalized = config.optionalize_defaults && typ.has_default;
45 writeln!(out, " Self {{").ok();
46 for field in &typ.fields {
47 if !config.exclude_types.is_empty()
49 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types)
50 {
51 continue;
52 }
53 let base_conversion = field_conversion_from_core_cfg(
54 &field.name,
55 &field.ty,
56 field.optional,
57 field.sanitized,
58 opaque_types,
59 config,
60 );
61 let base_conversion = if field.is_boxed && matches!(&field.ty, TypeRef::Named(_)) {
63 if field.optional {
64 let src = format!("{}: val.{}.map(Into::into)", field.name, field.name);
66 let dst = format!("{}: val.{}.map(|v| (*v).into())", field.name, field.name);
67 if base_conversion == src { dst } else { base_conversion }
68 } else {
69 base_conversion.replace(&format!("val.{}", field.name), &format!("(*val.{})", field.name))
71 }
72 } else {
73 base_conversion
74 };
75 let base_conversion = if field.newtype_wrapper.is_some() {
81 match &field.ty {
82 TypeRef::Optional(_) => {
83 base_conversion.replace(
85 &format!("val.{}", field.name),
86 &format!("val.{}.map(|v| v.0)", field.name),
87 )
88 }
89 TypeRef::Vec(_) => {
90 base_conversion.replace(
92 &format!("val.{}", field.name),
93 &format!("val.{}.iter().map(|v| v.0).collect::<Vec<_>>()", field.name),
94 )
95 }
96 _ if field.optional => base_conversion.replace(
99 &format!("val.{}", field.name),
100 &format!("val.{}.map(|v| v.0)", field.name),
101 ),
102 _ => {
103 base_conversion.replace(&format!("val.{}", field.name), &format!("val.{}.0", field.name))
105 }
106 }
107 } else {
108 base_conversion
109 };
110 let is_flattened_optional = field.optional && matches!(field.ty, TypeRef::Optional(_));
116 let base_conversion = if is_flattened_optional {
117 if let TypeRef::Optional(inner) = &field.ty {
118 let inner_conv = field_conversion_from_core_cfg(
120 &field.name,
121 inner.as_ref(),
122 true,
123 field.sanitized,
124 opaque_types,
125 config,
126 );
127 inner_conv.replace(&format!("val.{}", field.name), &format!("val.{}.flatten()", field.name))
129 } else {
130 base_conversion
131 }
132 } else {
133 base_conversion
134 };
135 let needs_some_wrap = !is_flattened_optional
139 && ((optionalized && !field.optional)
140 || (config.option_duration_on_defaults
141 && typ.has_default
142 && !field.optional
143 && matches!(field.ty, TypeRef::Duration)));
144 let conversion = if needs_some_wrap {
145 if let Some(expr) = base_conversion.strip_prefix(&format!("{}: ", field.name)) {
147 format!("{}: Some({})", field.name, expr)
148 } else {
149 base_conversion
150 }
151 } else {
152 base_conversion
153 };
154 let is_opaque_no_wrapper_field = field.core_wrapper == CoreWrapper::None
158 && matches!(&field.ty, TypeRef::Named(n) if config
159 .opaque_types
160 .is_some_and(|opaque| opaque.contains(n.as_str())));
161 let conversion = if is_opaque_no_wrapper_field {
167 format!("{}: Default::default()", field.name)
168 } else if !field.sanitized || field.core_wrapper == alef_core::ir::CoreWrapper::Cow {
169 apply_core_wrapper_from_core(
170 &conversion,
171 &field.name,
172 &field.core_wrapper,
173 &field.vec_inner_core_wrapper,
174 field.optional,
175 )
176 } else {
177 conversion
178 };
179 if field.cfg.is_some() {
181 continue;
182 }
183 let binding_field = config.binding_field_name_owned(&typ.name, &field.name);
187 let conversion = if binding_field != field.name {
188 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
189 format!("{binding_field}: {expr}")
190 } else {
191 conversion
192 }
193 } else {
194 conversion
195 };
196 writeln!(out, " {conversion},").ok();
197 }
198
199 writeln!(out, " }}").ok();
200 writeln!(out, " }}").ok();
201 write!(out, "}}").ok();
202 out
203}
204
205pub fn field_conversion_from_core(
208 name: &str,
209 ty: &TypeRef,
210 optional: bool,
211 sanitized: bool,
212 opaque_types: &AHashSet<String>,
213) -> String {
214 if sanitized {
218 if let TypeRef::Vec(inner) = ty {
221 if matches!(inner.as_ref(), TypeRef::Primitive(_)) {
222 if optional {
223 return format!(
224 "{name}: val.{name}.map(|t| {{ let arr: Vec<_> = [t.0, t.1].into_iter().map(|v| v as _).collect(); arr }})"
225 );
226 }
227 return format!("{name}: vec![val.{name}.0 as _, val.{name}.1 as _]");
228 }
229 }
230 if let TypeRef::Optional(opt_inner) = ty {
232 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
233 if matches!(vec_inner.as_ref(), TypeRef::Primitive(_)) {
234 return format!("{name}: val.{name}.map(|t| vec![t.0 as _, t.1 as _])");
235 }
236 }
237 }
238 if let TypeRef::Map(k, v) = ty {
240 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
241 if optional {
242 return format!(
243 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
244 );
245 }
246 return format!(
247 "{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()"
248 );
249 }
250 }
251 if let TypeRef::Vec(inner) = ty {
254 if matches!(inner.as_ref(), TypeRef::String) {
255 if optional {
256 return format!(
257 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
258 );
259 }
260 return format!("{name}: val.{name}.iter().map(|i| format!(\"{{:?}}\", i)).collect()");
261 }
262 }
263 if let TypeRef::Optional(opt_inner) = ty {
265 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
266 if matches!(vec_inner.as_ref(), TypeRef::String) {
267 return format!(
268 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
269 );
270 }
271 }
272 }
273 if matches!(ty, TypeRef::String) {
278 if optional {
279 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
280 }
281 return format!("{name}: format!(\"{{:?}}\", val.{name})");
282 }
283 if optional {
286 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
287 }
288 return format!("{name}: format!(\"{{:?}}\", val.{name})");
289 }
290 match ty {
291 TypeRef::Duration => {
293 if optional {
294 return format!("{name}: val.{name}.map(|d| d.as_millis() as u64)");
295 }
296 format!("{name}: val.{name}.as_millis() as u64")
297 }
298 TypeRef::Path => {
300 if optional {
301 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
302 } else {
303 format!("{name}: val.{name}.to_string_lossy().to_string()")
304 }
305 }
306 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
307 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
308 }
309 TypeRef::Char => {
311 if optional {
312 format!("{name}: val.{name}.map(|c| c.to_string())")
313 } else {
314 format!("{name}: val.{name}.to_string()")
315 }
316 }
317 TypeRef::Bytes => {
321 if optional {
322 format!("{name}: val.{name}.map(|v| v.to_vec().into())")
323 } else {
324 format!("{name}: val.{name}.to_vec().into()")
325 }
326 }
327 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
329 if optional {
330 format!("{name}: val.{name}.map(|v| {n} {{ inner: Arc::new(v) }})")
331 } else {
332 format!("{name}: {n} {{ inner: Arc::new(val.{name}) }}")
333 }
334 }
335 TypeRef::Json => {
337 if optional {
338 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
339 } else {
340 format!("{name}: val.{name}.to_string()")
341 }
342 }
343 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
344 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
345 }
346 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
347 if optional {
348 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.to_string()).collect())")
349 } else {
350 format!("{name}: val.{name}.iter().map(ToString::to_string).collect()")
351 }
352 }
353 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Optional(oi) if matches!(oi.as_ref(), TypeRef::Json)) => {
355 if optional {
356 format!(
357 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.as_ref().map(ToString::to_string)).collect())"
358 )
359 } else {
360 format!("{name}: val.{name}.iter().map(|i| i.as_ref().map(ToString::to_string)).collect()")
361 }
362 }
363 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Json) => {
368 if optional {
369 format!(
370 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
371 )
372 } else {
373 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()")
374 }
375 }
376 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
378 if optional {
379 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect())")
380 } else {
381 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v)).collect()")
382 }
383 }
384 TypeRef::Map(k, v) if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) => {
388 if optional {
389 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())")
390 } else {
391 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
392 }
393 }
394 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_)) => {
396 if optional {
397 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
398 } else {
399 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.into())).collect()")
400 }
401 }
402 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_))) =>
404 {
405 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
406 }
407 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
409 if optional {
410 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
411 } else {
412 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
413 }
414 }
415 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_))) =>
417 {
418 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
419 }
420 _ => field_conversion_to_core(name, ty, optional),
422 }
423}
424
425pub fn field_conversion_from_core_cfg(
427 name: &str,
428 ty: &TypeRef,
429 optional: bool,
430 sanitized: bool,
431 opaque_types: &AHashSet<String>,
432 config: &ConversionConfig,
433) -> String {
434 if sanitized {
439 if config.map_uses_jsvalue {
440 if let TypeRef::Map(k, v) = ty {
443 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
444 if optional {
445 return format!(
446 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
447 );
448 }
449 return format!(
450 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
451 );
452 }
453 }
454 if let TypeRef::Vec(inner) = ty {
456 if matches!(inner.as_ref(), TypeRef::Json) {
457 if optional {
458 return format!(
459 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
460 );
461 }
462 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
463 }
464 }
465 }
466 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
467 }
468
469 if config.vec_named_to_string {
473 if let TypeRef::Vec(inner) = ty {
474 if matches!(inner.as_ref(), TypeRef::Named(_)) {
475 if optional {
476 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok())");
477 }
478 return format!("{name}: serde_json::to_string(&val.{name}).unwrap_or_default()");
479 }
480 }
481 }
482
483 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
486 if optional {
487 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
488 }
489 return format!("{name}: format!(\"{{:?}}\", val.{name})");
490 }
491 if config.map_as_string {
492 if let TypeRef::Optional(inner) = ty {
493 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
494 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
495 }
496 }
497 }
498
499 if config.map_uses_jsvalue {
503 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
504 let is_map = matches!(ty, TypeRef::Map(_, _));
505 if is_nested_vec {
506 if optional {
507 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
508 }
509 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
510 }
511 if is_map {
512 if optional {
513 return format!(
514 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
515 );
516 }
517 return format!(
518 "{name}: js_sys::JSON::parse(&serde_json::to_string(&val.{name}).unwrap_or_default()).unwrap_or(JsValue::NULL)"
519 );
520 }
521 if let TypeRef::Optional(inner) = ty {
522 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
523 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
524 if is_inner_nested {
525 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
526 }
527 if is_inner_map {
528 return format!(
529 "{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok()).and_then(|s| js_sys::JSON::parse(&s).ok())"
530 );
531 }
532 }
533 }
534
535 let prefix = config.type_name_prefix;
536 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
537
538 match ty {
539 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
541 let cast_to = binding_prim_str(p);
542 if optional {
543 format!("{name}: val.{name}.map(|v| v as {cast_to})")
544 } else {
545 format!("{name}: val.{name} as {cast_to}")
546 }
547 }
548 TypeRef::Optional(inner)
550 if config.cast_large_ints_to_i64
551 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
552 {
553 if let TypeRef::Primitive(p) = inner.as_ref() {
554 let cast_to = binding_prim_str(p);
555 format!("{name}: val.{name}.map(|v| v as {cast_to})")
556 } else {
557 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
558 }
559 }
560 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
562 if optional {
563 format!("{name}: val.{name}.map(|v| v as i32)")
564 } else {
565 format!("{name}: val.{name} as i32")
566 }
567 }
568 TypeRef::Optional(inner)
570 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
571 {
572 format!("{name}: val.{name}.map(|v| v as i32)")
573 }
574 TypeRef::Vec(inner)
576 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
577 {
578 if let TypeRef::Primitive(_p) = inner.as_ref() {
579 if optional {
580 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as i32).collect())")
581 } else {
582 format!("{name}: val.{name}.iter().map(|&v| v as i32).collect()")
583 }
584 } else {
585 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
586 }
587 }
588 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
590 if optional {
591 format!("{name}: val.{name}.map(|v| v as f64)")
592 } else {
593 format!("{name}: val.{name} as f64")
594 }
595 }
596 TypeRef::Optional(inner)
598 if config.cast_large_ints_to_f64
599 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
600 {
601 format!("{name}: val.{name}.map(|v| v as f64)")
602 }
603 TypeRef::Vec(inner)
605 if config.cast_large_ints_to_f64
606 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
607 {
608 if optional {
609 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
610 } else {
611 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
612 }
613 }
614 TypeRef::Optional(inner)
616 if config.cast_large_ints_to_f64
617 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
618 {
619 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
620 }
621 TypeRef::Vec(outer)
623 if config.cast_large_ints_to_f64
624 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p))) =>
625 {
626 if optional {
627 format!(
628 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
629 )
630 } else {
631 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
632 }
633 }
634 TypeRef::Optional(inner)
636 if config.cast_large_ints_to_f64
637 && 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)))) =>
638 {
639 format!(
640 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
641 )
642 }
643 TypeRef::Map(_k, v)
645 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
646 {
647 if optional {
648 format!("{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as f64)).collect())")
649 } else {
650 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as f64)).collect()")
651 }
652 }
653 TypeRef::Duration if config.cast_large_ints_to_f64 => {
655 if optional {
656 format!("{name}: val.{name}.map(|d| d.as_millis() as f64)")
657 } else {
658 format!("{name}: val.{name}.as_millis() as f64")
659 }
660 }
661 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
663 if optional {
664 format!("{name}: val.{name}.map(|v| v as f64)")
665 } else {
666 format!("{name}: val.{name} as f64")
667 }
668 }
669 TypeRef::Duration if config.cast_large_ints_to_i64 => {
671 if optional {
672 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
673 } else {
674 format!("{name}: val.{name}.as_millis() as u64 as i64")
675 }
676 }
677 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
679 let prefixed = format!("{prefix}{n}");
680 if optional {
681 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
682 } else {
683 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
684 }
685 }
686 TypeRef::Named(n) if is_enum_string(n) => {
688 if optional {
691 format!(
692 "{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())"
693 )
694 } else {
695 format!(
696 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
697 )
698 }
699 }
700 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
702 if optional {
703 format!(
704 "{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())"
705 )
706 } else {
707 format!(
708 "{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()"
709 )
710 }
711 }
712 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
714 {
715 format!(
716 "{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())"
717 )
718 }
719 TypeRef::Vec(inner)
721 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
722 {
723 if optional {
724 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
725 } else {
726 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
727 }
728 }
729 TypeRef::Optional(inner)
731 if config.cast_f32_to_f64
732 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
733 {
734 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
735 }
736 TypeRef::Optional(inner)
738 if config.cast_large_ints_to_i64
739 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
740 {
741 if let TypeRef::Vec(vi) = inner.as_ref() {
742 if let TypeRef::Primitive(p) = vi.as_ref() {
743 let cast_to = binding_prim_str(p);
744 if sanitized {
745 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
747 } else {
748 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
749 }
750 } else {
751 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
752 }
753 } else {
754 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
755 }
756 }
757 TypeRef::Vec(outer)
759 if config.cast_f32_to_f64
760 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
761 {
762 if optional {
763 format!(
764 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
765 )
766 } else {
767 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
768 }
769 }
770 TypeRef::Optional(inner)
772 if config.cast_f32_to_f64
773 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
774 {
775 format!(
776 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
777 )
778 }
779 TypeRef::Optional(inner)
781 if config.cast_large_ints_to_i64
782 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
783 {
784 if let TypeRef::Primitive(p) = inner.as_ref() {
785 let cast_to = binding_prim_str(p);
786 format!("{name}: val.{name}.map(|v| v as {cast_to})")
787 } else {
788 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
789 }
790 }
791 TypeRef::Map(_k, v)
793 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
794 {
795 if let TypeRef::Primitive(p) = v.as_ref() {
796 let cast_to = binding_prim_str(p);
797 if optional {
798 format!(
799 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
800 )
801 } else {
802 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
803 }
804 } else {
805 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
806 }
807 }
808 TypeRef::Vec(inner)
810 if config.cast_large_ints_to_i64
811 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
812 {
813 if let TypeRef::Primitive(p) = inner.as_ref() {
814 let cast_to = binding_prim_str(p);
815 if sanitized {
816 if optional {
818 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
819 } else {
820 format!("{name}: {{ let (a, b) = val.{name}; vec![a as {cast_to}, b as {cast_to}] }}")
821 }
822 } else if optional {
823 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
824 } else {
825 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
826 }
827 } else {
828 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
829 }
830 }
831 TypeRef::Vec(outer)
833 if config.cast_large_ints_to_i64
834 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
835 {
836 if let TypeRef::Vec(inner) = outer.as_ref() {
837 if let TypeRef::Primitive(p) = inner.as_ref() {
838 let cast_to = binding_prim_str(p);
839 if optional {
840 format!(
841 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
842 )
843 } else {
844 format!(
845 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
846 )
847 }
848 } else {
849 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
850 }
851 } else {
852 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
853 }
854 }
855 TypeRef::Json if config.json_to_string => {
857 if optional {
858 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
859 } else {
860 format!("{name}: val.{name}.to_string()")
861 }
862 }
863 TypeRef::Json if config.map_uses_jsvalue => {
865 if optional {
866 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
867 } else {
868 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
869 }
870 }
871 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
873 if optional {
874 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
875 } else {
876 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
877 }
878 }
879 TypeRef::Optional(inner)
881 if config.map_uses_jsvalue
882 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
883 {
884 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
885 }
886 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
888 }
889}
890
891fn apply_core_wrapper_from_core(
894 conversion: &str,
895 name: &str,
896 core_wrapper: &CoreWrapper,
897 vec_inner_core_wrapper: &CoreWrapper,
898 optional: bool,
899) -> String {
900 if *vec_inner_core_wrapper == CoreWrapper::Arc {
902 return conversion
903 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
904 .replace(
905 "map(|v| v.into_iter().map(Into::into)",
906 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
907 );
908 }
909
910 match core_wrapper {
911 CoreWrapper::None => conversion.to_string(),
912 CoreWrapper::Cow => {
913 let prefix = format!("{name}: ");
920 let already_some_wrapped = conversion
921 .strip_prefix(&prefix)
922 .is_some_and(|expr| expr.starts_with("Some("));
923 if optional {
924 format!("{name}: val.{name}.as_ref().map(|v| v.to_string())")
925 } else if already_some_wrapped {
926 format!("{name}: Some(val.{name}.to_string())")
927 } else {
928 format!("{name}: val.{name}.to_string()")
929 }
930 }
931 CoreWrapper::Arc => {
932 if conversion.contains("{ inner: Arc::new(") {
941 return conversion.replace("{ inner: Arc::new(v) }", "{ inner: v }").replace(
942 &format!("{{ inner: Arc::new(val.{name}) }}"),
943 &format!("{{ inner: val.{name} }}"),
944 );
945 }
946 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
947 if optional {
948 let simple_passthrough = format!("val.{name}");
957 if expr == simple_passthrough {
958 format!("{name}: {expr}.map(|v| (*v).clone().into())")
959 } else {
960 format!("{name}: {expr}")
961 }
962 } else {
963 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
964 format!("{name}: {unwrapped}")
965 }
966 } else {
967 conversion.to_string()
968 }
969 }
970 CoreWrapper::Bytes => {
971 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
976 let already_converted_non_opt = expr == format!("val.{name}.to_vec().into()");
977 let already_converted_opt = expr == format!("val.{name}.map(|v| v.to_vec().into())");
978 if already_converted_non_opt || already_converted_opt {
979 conversion.to_string()
980 } else if optional {
981 format!("{name}: {expr}.map(|v| v.to_vec().into())")
982 } else if expr == format!("val.{name}") {
983 format!("{name}: val.{name}.to_vec().into()")
984 } else {
985 conversion.to_string()
986 }
987 } else {
988 conversion.to_string()
989 }
990 }
991 CoreWrapper::ArcMutex => {
992 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
994 if optional {
995 format!("{name}: {expr}.map(|v| v.lock().unwrap().clone().into())")
996 } else if expr == format!("val.{name}") {
997 format!("{name}: val.{name}.lock().unwrap().clone().into()")
998 } else {
999 conversion.to_string()
1000 }
1001 } else {
1002 conversion.to_string()
1003 }
1004 }
1005 }
1006}