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 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 conversion = if !field.sanitized {
157 apply_core_wrapper_from_core(
158 &conversion,
159 &field.name,
160 &field.core_wrapper,
161 &field.vec_inner_core_wrapper,
162 field.optional,
163 )
164 } else {
165 conversion
166 };
167 if field.cfg.is_some() {
169 continue;
170 }
171 let binding_field = config.binding_field_name_owned(&typ.name, &field.name);
175 let conversion = if binding_field != field.name {
176 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
177 format!("{binding_field}: {expr}")
178 } else {
179 conversion
180 }
181 } else {
182 conversion
183 };
184 writeln!(out, " {conversion},").ok();
185 }
186
187 writeln!(out, " }}").ok();
188 writeln!(out, " }}").ok();
189 write!(out, "}}").ok();
190 out
191}
192
193pub fn field_conversion_from_core(
196 name: &str,
197 ty: &TypeRef,
198 optional: bool,
199 sanitized: bool,
200 opaque_types: &AHashSet<String>,
201) -> String {
202 if sanitized {
206 if let TypeRef::Vec(inner) = ty {
209 if matches!(inner.as_ref(), TypeRef::Primitive(_)) {
210 if optional {
211 return format!(
212 "{name}: val.{name}.map(|t| {{ let arr: Vec<_> = [t.0, t.1].into_iter().map(|v| v as _).collect(); arr }})"
213 );
214 }
215 return format!("{name}: vec![val.{name}.0 as _, val.{name}.1 as _]");
216 }
217 }
218 if let TypeRef::Optional(opt_inner) = ty {
220 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
221 if matches!(vec_inner.as_ref(), TypeRef::Primitive(_)) {
222 return format!("{name}: val.{name}.map(|t| vec![t.0 as _, t.1 as _])");
223 }
224 }
225 }
226 if let TypeRef::Map(k, v) = ty {
228 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
229 if optional {
230 return format!(
231 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
232 );
233 }
234 return format!(
235 "{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()"
236 );
237 }
238 }
239 if let TypeRef::Vec(inner) = ty {
242 if matches!(inner.as_ref(), TypeRef::String) {
243 if optional {
244 return format!(
245 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
246 );
247 }
248 return format!("{name}: val.{name}.iter().map(|i| format!(\"{{:?}}\", i)).collect()");
249 }
250 }
251 if let TypeRef::Optional(opt_inner) = ty {
253 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
254 if matches!(vec_inner.as_ref(), TypeRef::String) {
255 return format!(
256 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
257 );
258 }
259 }
260 }
261 if matches!(ty, TypeRef::String) {
265 if optional {
266 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
267 }
268 return format!("{name}: format!(\"{{:?}}\", val.{name})");
269 }
270 if optional {
273 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
274 }
275 return format!("{name}: format!(\"{{:?}}\", val.{name})");
276 }
277 match ty {
278 TypeRef::Duration => {
280 if optional {
281 return format!("{name}: val.{name}.map(|d| d.as_millis() as u64)");
282 }
283 format!("{name}: val.{name}.as_millis() as u64")
284 }
285 TypeRef::Path => {
287 if optional {
288 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
289 } else {
290 format!("{name}: val.{name}.to_string_lossy().to_string()")
291 }
292 }
293 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
294 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
295 }
296 TypeRef::Char => {
298 if optional {
299 format!("{name}: val.{name}.map(|c| c.to_string())")
300 } else {
301 format!("{name}: val.{name}.to_string()")
302 }
303 }
304 TypeRef::Bytes => {
306 if optional {
307 format!("{name}: val.{name}.map(|v| v.to_vec())")
308 } else {
309 format!("{name}: val.{name}.to_vec()")
310 }
311 }
312 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
314 if optional {
315 format!("{name}: val.{name}.map(|v| {n} {{ inner: Arc::new(v) }})")
316 } else {
317 format!("{name}: {n} {{ inner: Arc::new(val.{name}) }}")
318 }
319 }
320 TypeRef::Json => {
322 if optional {
323 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
324 } else {
325 format!("{name}: val.{name}.to_string()")
326 }
327 }
328 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
329 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
330 }
331 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
332 if optional {
333 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.to_string()).collect())")
334 } else {
335 format!("{name}: val.{name}.iter().map(ToString::to_string).collect()")
336 }
337 }
338 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Optional(oi) if matches!(oi.as_ref(), TypeRef::Json)) => {
340 if optional {
341 format!(
342 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.as_ref().map(ToString::to_string)).collect())"
343 )
344 } else {
345 format!("{name}: val.{name}.iter().map(|i| i.as_ref().map(ToString::to_string)).collect()")
346 }
347 }
348 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
350 let k_is_json = matches!(k.as_ref(), TypeRef::Json);
351 let k_expr = if k_is_json { "k.to_string()" } else { "k" };
352 if optional {
353 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, v.to_string())).collect())")
354 } else {
355 format!("{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, v.to_string())).collect()")
356 }
357 }
358 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
360 if optional {
361 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect())")
362 } else {
363 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v)).collect()")
364 }
365 }
366 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_)) => {
368 if optional {
369 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
370 } else {
371 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.into())).collect()")
372 }
373 }
374 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_))) =>
376 {
377 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
378 }
379 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
381 if optional {
382 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
383 } else {
384 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
385 }
386 }
387 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_))) =>
389 {
390 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
391 }
392 _ => field_conversion_to_core(name, ty, optional),
394 }
395}
396
397pub fn field_conversion_from_core_cfg(
399 name: &str,
400 ty: &TypeRef,
401 optional: bool,
402 sanitized: bool,
403 opaque_types: &AHashSet<String>,
404 config: &ConversionConfig,
405) -> String {
406 if sanitized {
411 if config.map_uses_jsvalue {
412 if let TypeRef::Map(k, v) = ty {
414 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
415 if optional {
416 return format!(
417 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
418 );
419 }
420 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
421 }
422 }
423 if let TypeRef::Vec(inner) = ty {
425 if matches!(inner.as_ref(), TypeRef::Json) {
426 if optional {
427 return format!(
428 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
429 );
430 }
431 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
432 }
433 }
434 }
435 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
436 }
437
438 if config.vec_named_to_string {
442 if let TypeRef::Vec(inner) = ty {
443 if matches!(inner.as_ref(), TypeRef::Named(_)) {
444 if optional {
445 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok())");
446 }
447 return format!("{name}: serde_json::to_string(&val.{name}).unwrap_or_default()");
448 }
449 }
450 }
451
452 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
455 if optional {
456 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
457 }
458 return format!("{name}: format!(\"{{:?}}\", val.{name})");
459 }
460 if config.map_as_string {
461 if let TypeRef::Optional(inner) = ty {
462 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
463 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
464 }
465 }
466 }
467
468 if config.map_uses_jsvalue {
470 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
471 let is_map = matches!(ty, TypeRef::Map(_, _));
472 if is_nested_vec || is_map {
473 if optional {
474 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
475 }
476 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
477 }
478 if let TypeRef::Optional(inner) = ty {
479 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
480 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
481 if is_inner_nested || is_inner_map {
482 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
483 }
484 }
485 }
486
487 let prefix = config.type_name_prefix;
488 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
489
490 match ty {
491 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
493 let cast_to = binding_prim_str(p);
494 if optional {
495 format!("{name}: val.{name}.map(|v| v as {cast_to})")
496 } else {
497 format!("{name}: val.{name} as {cast_to}")
498 }
499 }
500 TypeRef::Optional(inner)
502 if config.cast_large_ints_to_i64
503 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
504 {
505 if let TypeRef::Primitive(p) = inner.as_ref() {
506 let cast_to = binding_prim_str(p);
507 format!("{name}: val.{name}.map(|v| v as {cast_to})")
508 } else {
509 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
510 }
511 }
512 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
514 if optional {
515 format!("{name}: val.{name}.map(|v| v as f64)")
516 } else {
517 format!("{name}: val.{name} as f64")
518 }
519 }
520 TypeRef::Duration if config.cast_large_ints_to_i64 => {
522 if optional {
523 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
524 } else {
525 format!("{name}: val.{name}.as_millis() as u64 as i64")
526 }
527 }
528 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
530 let prefixed = format!("{prefix}{n}");
531 if optional {
532 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
533 } else {
534 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
535 }
536 }
537 TypeRef::Named(n) if is_enum_string(n) => {
539 if optional {
542 format!(
543 "{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())"
544 )
545 } else {
546 format!(
547 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
548 )
549 }
550 }
551 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
553 if optional {
554 format!(
555 "{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())"
556 )
557 } else {
558 format!(
559 "{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()"
560 )
561 }
562 }
563 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
565 {
566 format!(
567 "{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())"
568 )
569 }
570 TypeRef::Vec(inner)
572 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
573 {
574 if optional {
575 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
576 } else {
577 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
578 }
579 }
580 TypeRef::Optional(inner)
582 if config.cast_f32_to_f64
583 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
584 {
585 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
586 }
587 TypeRef::Optional(inner)
589 if config.cast_large_ints_to_i64
590 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
591 {
592 if let TypeRef::Vec(vi) = inner.as_ref() {
593 if let TypeRef::Primitive(p) = vi.as_ref() {
594 let cast_to = binding_prim_str(p);
595 if sanitized {
596 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
598 } else {
599 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
600 }
601 } else {
602 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
603 }
604 } else {
605 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
606 }
607 }
608 TypeRef::Vec(outer)
610 if config.cast_f32_to_f64
611 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
612 {
613 if optional {
614 format!(
615 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
616 )
617 } else {
618 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
619 }
620 }
621 TypeRef::Optional(inner)
623 if config.cast_f32_to_f64
624 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
625 {
626 format!(
627 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
628 )
629 }
630 TypeRef::Optional(inner)
632 if config.cast_large_ints_to_i64
633 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
634 {
635 if let TypeRef::Primitive(p) = inner.as_ref() {
636 let cast_to = binding_prim_str(p);
637 format!("{name}: val.{name}.map(|v| v as {cast_to})")
638 } else {
639 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
640 }
641 }
642 TypeRef::Map(_k, v)
644 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
645 {
646 if let TypeRef::Primitive(p) = v.as_ref() {
647 let cast_to = binding_prim_str(p);
648 if optional {
649 format!(
650 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
651 )
652 } else {
653 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
654 }
655 } else {
656 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
657 }
658 }
659 TypeRef::Vec(inner)
661 if config.cast_large_ints_to_i64
662 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
663 {
664 if let TypeRef::Primitive(p) = inner.as_ref() {
665 let cast_to = binding_prim_str(p);
666 if sanitized {
667 if optional {
669 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
670 } else {
671 format!("{name}: {{ let (a, b) = val.{name}; vec![a as {cast_to}, b as {cast_to}] }}")
672 }
673 } else if optional {
674 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
675 } else {
676 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
677 }
678 } else {
679 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
680 }
681 }
682 TypeRef::Vec(outer)
684 if config.cast_large_ints_to_i64
685 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
686 {
687 if let TypeRef::Vec(inner) = outer.as_ref() {
688 if let TypeRef::Primitive(p) = inner.as_ref() {
689 let cast_to = binding_prim_str(p);
690 if optional {
691 format!(
692 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
693 )
694 } else {
695 format!(
696 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
697 )
698 }
699 } else {
700 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
701 }
702 } else {
703 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
704 }
705 }
706 TypeRef::Json if config.json_to_string => {
708 if optional {
709 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
710 } else {
711 format!("{name}: val.{name}.to_string()")
712 }
713 }
714 TypeRef::Json if config.map_uses_jsvalue => {
716 if optional {
717 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
718 } else {
719 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
720 }
721 }
722 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
724 if optional {
725 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
726 } else {
727 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
728 }
729 }
730 TypeRef::Optional(inner)
732 if config.map_uses_jsvalue
733 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
734 {
735 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
736 }
737 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
739 }
740}
741
742fn apply_core_wrapper_from_core(
745 conversion: &str,
746 name: &str,
747 core_wrapper: &CoreWrapper,
748 vec_inner_core_wrapper: &CoreWrapper,
749 optional: bool,
750) -> String {
751 if *vec_inner_core_wrapper == CoreWrapper::Arc {
753 return conversion
754 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
755 .replace(
756 "map(|v| v.into_iter().map(Into::into)",
757 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
758 );
759 }
760
761 match core_wrapper {
762 CoreWrapper::None => conversion.to_string(),
763 CoreWrapper::Cow => {
764 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
769 if optional {
770 conversion.to_string()
772 } else if expr == format!("val.{name}") {
773 format!("{name}: val.{name}.into_owned()")
774 } else {
775 conversion.to_string()
776 }
777 } else {
778 conversion.to_string()
779 }
780 }
781 CoreWrapper::Arc => {
782 if conversion.contains("{ inner: Arc::new(") {
791 return conversion.replace("{ inner: Arc::new(v) }", "{ inner: v }").replace(
792 &format!("{{ inner: Arc::new(val.{name}) }}"),
793 &format!("{{ inner: val.{name} }}"),
794 );
795 }
796 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
797 if optional {
798 format!("{name}: {expr}.map(|v| (*v).clone().into())")
799 } else {
800 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
801 format!("{name}: {unwrapped}")
802 }
803 } else {
804 conversion.to_string()
805 }
806 }
807 CoreWrapper::Bytes => {
808 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
810 if optional {
811 format!("{name}: {expr}.map(|v| v.to_vec())")
812 } else if expr == format!("val.{name}") {
813 format!("{name}: val.{name}.to_vec()")
814 } else {
815 conversion.to_string()
816 }
817 } else {
818 conversion.to_string()
819 }
820 }
821 CoreWrapper::ArcMutex => {
822 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
824 if optional {
825 format!("{name}: {expr}.map(|v| v.lock().unwrap().clone().into())")
826 } else if expr == format!("val.{name}") {
827 format!("{name}: val.{name}.lock().unwrap().clone().into()")
828 } else {
829 conversion.to_string()
830 }
831 } else {
832 conversion.to_string()
833 }
834 }
835 }
836}