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_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 if config.force_default_fields.contains(&field.name.as_str()) {
57 let needs_some_wrap = !field.optional && (config.optionalize_defaults && typ.has_default);
58 let expr = if needs_some_wrap {
59 format!("{}: Some(Default::default())", field.name)
60 } else {
61 format!("{}: Default::default()", field.name)
62 };
63 writeln!(out, " {expr},").ok();
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 conversion = if !field.sanitized || field.core_wrapper == alef_core::ir::CoreWrapper::Cow {
173 apply_core_wrapper_from_core(
174 &conversion,
175 &field.name,
176 &field.core_wrapper,
177 &field.vec_inner_core_wrapper,
178 field.optional,
179 )
180 } else {
181 conversion
182 };
183 if field.cfg.is_some() {
185 continue;
186 }
187 let binding_field = config.binding_field_name_owned(&typ.name, &field.name);
191 let conversion = if binding_field != field.name {
192 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
193 format!("{binding_field}: {expr}")
194 } else {
195 conversion
196 }
197 } else {
198 conversion
199 };
200 writeln!(out, " {conversion},").ok();
201 }
202
203 writeln!(out, " }}").ok();
204 writeln!(out, " }}").ok();
205 write!(out, "}}").ok();
206 out
207}
208
209pub fn field_conversion_from_core(
212 name: &str,
213 ty: &TypeRef,
214 optional: bool,
215 sanitized: bool,
216 opaque_types: &AHashSet<String>,
217) -> String {
218 if sanitized {
222 if let TypeRef::Vec(inner) = ty {
225 if matches!(inner.as_ref(), TypeRef::Primitive(_)) {
226 if optional {
227 return format!(
228 "{name}: val.{name}.map(|t| {{ let arr: Vec<_> = [t.0, t.1].into_iter().map(|v| v as _).collect(); arr }})"
229 );
230 }
231 return format!("{name}: vec![val.{name}.0 as _, val.{name}.1 as _]");
232 }
233 }
234 if let TypeRef::Optional(opt_inner) = ty {
236 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
237 if matches!(vec_inner.as_ref(), TypeRef::Primitive(_)) {
238 return format!("{name}: val.{name}.map(|t| vec![t.0 as _, t.1 as _])");
239 }
240 }
241 }
242 if let TypeRef::Map(k, v) = ty {
244 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
245 if optional {
246 return format!(
247 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
248 );
249 }
250 return format!(
251 "{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()"
252 );
253 }
254 }
255 if let TypeRef::Vec(inner) = ty {
258 if matches!(inner.as_ref(), TypeRef::String) {
259 if optional {
260 return format!(
261 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
262 );
263 }
264 return format!("{name}: val.{name}.iter().map(|i| format!(\"{{:?}}\", i)).collect()");
265 }
266 }
267 if let TypeRef::Optional(opt_inner) = ty {
269 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
270 if matches!(vec_inner.as_ref(), TypeRef::String) {
271 return format!(
272 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
273 );
274 }
275 }
276 }
277 if matches!(ty, TypeRef::String) {
282 if optional {
283 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
284 }
285 return format!("{name}: format!(\"{{:?}}\", val.{name})");
286 }
287 if optional {
290 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
291 }
292 return format!("{name}: format!(\"{{:?}}\", val.{name})");
293 }
294 match ty {
295 TypeRef::Duration => {
297 if optional {
298 return format!("{name}: val.{name}.map(|d| d.as_millis() as u64)");
299 }
300 format!("{name}: val.{name}.as_millis() as u64")
301 }
302 TypeRef::Path => {
304 if optional {
305 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
306 } else {
307 format!("{name}: val.{name}.to_string_lossy().to_string()")
308 }
309 }
310 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
311 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
312 }
313 TypeRef::Char => {
315 if optional {
316 format!("{name}: val.{name}.map(|c| c.to_string())")
317 } else {
318 format!("{name}: val.{name}.to_string()")
319 }
320 }
321 TypeRef::Bytes => {
323 if optional {
324 format!("{name}: val.{name}.map(|v| v.to_vec())")
325 } else {
326 format!("{name}: val.{name}.to_vec()")
327 }
328 }
329 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
331 if optional {
332 format!("{name}: val.{name}.map(|v| {n} {{ inner: Arc::new(v) }})")
333 } else {
334 format!("{name}: {n} {{ inner: Arc::new(val.{name}) }}")
335 }
336 }
337 TypeRef::Json => {
339 if optional {
340 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
341 } else {
342 format!("{name}: val.{name}.to_string()")
343 }
344 }
345 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
346 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
347 }
348 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
349 if optional {
350 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.to_string()).collect())")
351 } else {
352 format!("{name}: val.{name}.iter().map(ToString::to_string).collect()")
353 }
354 }
355 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Optional(oi) if matches!(oi.as_ref(), TypeRef::Json)) => {
357 if optional {
358 format!(
359 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.as_ref().map(ToString::to_string)).collect())"
360 )
361 } else {
362 format!("{name}: val.{name}.iter().map(|i| i.as_ref().map(ToString::to_string)).collect()")
363 }
364 }
365 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Json) => {
370 if optional {
371 format!(
372 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
373 )
374 } else {
375 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()")
376 }
377 }
378 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
380 if optional {
381 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect())")
382 } else {
383 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v)).collect()")
384 }
385 }
386 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_)) => {
388 if optional {
389 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
390 } else {
391 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.into())).collect()")
392 }
393 }
394 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_))) =>
396 {
397 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
398 }
399 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
401 if optional {
402 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
403 } else {
404 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
405 }
406 }
407 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_))) =>
409 {
410 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
411 }
412 _ => field_conversion_to_core(name, ty, optional),
414 }
415}
416
417pub fn field_conversion_from_core_cfg(
419 name: &str,
420 ty: &TypeRef,
421 optional: bool,
422 sanitized: bool,
423 opaque_types: &AHashSet<String>,
424 config: &ConversionConfig,
425) -> String {
426 if sanitized {
431 if config.map_uses_jsvalue {
432 if let TypeRef::Map(k, v) = ty {
434 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
435 if optional {
436 return format!(
437 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
438 );
439 }
440 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
441 }
442 }
443 if let TypeRef::Vec(inner) = ty {
445 if matches!(inner.as_ref(), TypeRef::Json) {
446 if optional {
447 return format!(
448 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
449 );
450 }
451 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
452 }
453 }
454 let is_handle_type = matches!(ty, TypeRef::Named(_))
457 || matches!(ty, TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Named(_)));
458 if is_handle_type {
459 return format!("{name}: None");
460 }
461 }
462 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
463 }
464
465 if config.vec_named_to_string {
469 if let TypeRef::Vec(inner) = ty {
470 if matches!(inner.as_ref(), TypeRef::Named(_)) {
471 if optional {
472 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok())");
473 }
474 return format!("{name}: serde_json::to_string(&val.{name}).unwrap_or_default()");
475 }
476 }
477 }
478
479 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
482 if optional {
483 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
484 }
485 return format!("{name}: format!(\"{{:?}}\", val.{name})");
486 }
487 if config.map_as_string {
488 if let TypeRef::Optional(inner) = ty {
489 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
490 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
491 }
492 }
493 }
494
495 if config.map_uses_jsvalue {
497 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
498 let is_map = matches!(ty, TypeRef::Map(_, _));
499 if is_nested_vec || is_map {
500 if optional {
501 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
502 }
503 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
504 }
505 if let TypeRef::Optional(inner) = ty {
506 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
507 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
508 if is_inner_nested || is_inner_map {
509 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
510 }
511 }
512 }
513
514 let prefix = config.type_name_prefix;
515 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
516
517 match ty {
518 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
520 let cast_to = binding_prim_str(p);
521 if optional {
522 format!("{name}: val.{name}.map(|v| v as {cast_to})")
523 } else {
524 format!("{name}: val.{name} as {cast_to}")
525 }
526 }
527 TypeRef::Optional(inner)
529 if config.cast_large_ints_to_i64
530 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
531 {
532 if let TypeRef::Primitive(p) = inner.as_ref() {
533 let cast_to = binding_prim_str(p);
534 format!("{name}: val.{name}.map(|v| v as {cast_to})")
535 } else {
536 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
537 }
538 }
539 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
541 if optional {
542 format!("{name}: val.{name}.map(|v| v as f64)")
543 } else {
544 format!("{name}: val.{name} as f64")
545 }
546 }
547 TypeRef::Duration if config.cast_large_ints_to_i64 => {
549 if optional {
550 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
551 } else {
552 format!("{name}: val.{name}.as_millis() as u64 as i64")
553 }
554 }
555 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
557 let prefixed = format!("{prefix}{n}");
558 if optional {
559 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
560 } else {
561 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
562 }
563 }
564 TypeRef::Named(n) if is_enum_string(n) => {
566 if optional {
569 format!(
570 "{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())"
571 )
572 } else {
573 format!(
574 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
575 )
576 }
577 }
578 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
580 if optional {
581 format!(
582 "{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())"
583 )
584 } else {
585 format!(
586 "{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()"
587 )
588 }
589 }
590 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
592 {
593 format!(
594 "{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())"
595 )
596 }
597 TypeRef::Vec(inner)
599 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
600 {
601 if optional {
602 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
603 } else {
604 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
605 }
606 }
607 TypeRef::Optional(inner)
609 if config.cast_f32_to_f64
610 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
611 {
612 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
613 }
614 TypeRef::Optional(inner)
616 if config.cast_large_ints_to_i64
617 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
618 {
619 if let TypeRef::Vec(vi) = inner.as_ref() {
620 if let TypeRef::Primitive(p) = vi.as_ref() {
621 let cast_to = binding_prim_str(p);
622 if sanitized {
623 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
625 } else {
626 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
627 }
628 } else {
629 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
630 }
631 } else {
632 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
633 }
634 }
635 TypeRef::Vec(outer)
637 if config.cast_f32_to_f64
638 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
639 {
640 if optional {
641 format!(
642 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
643 )
644 } else {
645 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
646 }
647 }
648 TypeRef::Optional(inner)
650 if config.cast_f32_to_f64
651 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
652 {
653 format!(
654 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
655 )
656 }
657 TypeRef::Optional(inner)
659 if config.cast_large_ints_to_i64
660 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
661 {
662 if let TypeRef::Primitive(p) = inner.as_ref() {
663 let cast_to = binding_prim_str(p);
664 format!("{name}: val.{name}.map(|v| v as {cast_to})")
665 } else {
666 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
667 }
668 }
669 TypeRef::Map(_k, v)
671 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
672 {
673 if let TypeRef::Primitive(p) = v.as_ref() {
674 let cast_to = binding_prim_str(p);
675 if optional {
676 format!(
677 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
678 )
679 } else {
680 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
681 }
682 } else {
683 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
684 }
685 }
686 TypeRef::Vec(inner)
688 if config.cast_large_ints_to_i64
689 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
690 {
691 if let TypeRef::Primitive(p) = inner.as_ref() {
692 let cast_to = binding_prim_str(p);
693 if sanitized {
694 if optional {
696 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
697 } else {
698 format!("{name}: {{ let (a, b) = val.{name}; vec![a as {cast_to}, b as {cast_to}] }}")
699 }
700 } else if optional {
701 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
702 } else {
703 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
704 }
705 } else {
706 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
707 }
708 }
709 TypeRef::Vec(outer)
711 if config.cast_large_ints_to_i64
712 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
713 {
714 if let TypeRef::Vec(inner) = outer.as_ref() {
715 if let TypeRef::Primitive(p) = inner.as_ref() {
716 let cast_to = binding_prim_str(p);
717 if optional {
718 format!(
719 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
720 )
721 } else {
722 format!(
723 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
724 )
725 }
726 } else {
727 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
728 }
729 } else {
730 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
731 }
732 }
733 TypeRef::Json if config.json_to_string => {
735 if optional {
736 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
737 } else {
738 format!("{name}: val.{name}.to_string()")
739 }
740 }
741 TypeRef::Json if config.map_uses_jsvalue => {
743 if optional {
744 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
745 } else {
746 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
747 }
748 }
749 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
751 if optional {
752 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
753 } else {
754 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
755 }
756 }
757 TypeRef::Optional(inner)
759 if config.map_uses_jsvalue
760 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
761 {
762 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
763 }
764 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
766 }
767}
768
769fn apply_core_wrapper_from_core(
772 conversion: &str,
773 name: &str,
774 core_wrapper: &CoreWrapper,
775 vec_inner_core_wrapper: &CoreWrapper,
776 optional: bool,
777) -> String {
778 if *vec_inner_core_wrapper == CoreWrapper::Arc {
780 return conversion
781 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
782 .replace(
783 "map(|v| v.into_iter().map(Into::into)",
784 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
785 );
786 }
787
788 match core_wrapper {
789 CoreWrapper::None => conversion.to_string(),
790 CoreWrapper::Cow => {
791 let prefix = format!("{name}: ");
798 let already_some_wrapped = conversion
799 .strip_prefix(&prefix)
800 .is_some_and(|expr| expr.starts_with("Some("));
801 if optional {
802 format!("{name}: val.{name}.as_ref().map(|v| v.to_string())")
803 } else if already_some_wrapped {
804 format!("{name}: Some(val.{name}.to_string())")
805 } else {
806 format!("{name}: val.{name}.to_string()")
807 }
808 }
809 CoreWrapper::Arc => {
810 if conversion.contains("{ inner: Arc::new(") {
819 return conversion.replace("{ inner: Arc::new(v) }", "{ inner: v }").replace(
820 &format!("{{ inner: Arc::new(val.{name}) }}"),
821 &format!("{{ inner: val.{name} }}"),
822 );
823 }
824 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
825 if optional {
826 let simple_passthrough = format!("val.{name}");
835 if expr == simple_passthrough {
836 format!("{name}: {expr}.map(|v| (*v).clone().into())")
837 } else {
838 format!("{name}: {expr}")
839 }
840 } else {
841 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
842 format!("{name}: {unwrapped}")
843 }
844 } else {
845 conversion.to_string()
846 }
847 }
848 CoreWrapper::Bytes => {
849 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
851 if optional {
852 format!("{name}: {expr}.map(|v| v.to_vec())")
853 } else if expr == format!("val.{name}") {
854 format!("{name}: val.{name}.to_vec()")
855 } else {
856 conversion.to_string()
857 }
858 } else {
859 conversion.to_string()
860 }
861 }
862 CoreWrapper::ArcMutex => {
863 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
865 if optional {
866 format!("{name}: {expr}.map(|v| v.lock().unwrap().clone().into())")
867 } else if expr == format!("val.{name}") {
868 format!("{name}: val.{name}.lock().unwrap().clone().into()")
869 } else {
870 conversion.to_string()
871 }
872 } else {
873 conversion.to_string()
874 }
875 }
876 }
877}