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 || field.core_wrapper == alef_core::ir::CoreWrapper::Cow {
160 apply_core_wrapper_from_core(
161 &conversion,
162 &field.name,
163 &field.core_wrapper,
164 &field.vec_inner_core_wrapper,
165 field.optional,
166 )
167 } else {
168 conversion
169 };
170 if field.cfg.is_some() {
172 continue;
173 }
174 let binding_field = config.binding_field_name_owned(&typ.name, &field.name);
178 let conversion = if binding_field != field.name {
179 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
180 format!("{binding_field}: {expr}")
181 } else {
182 conversion
183 }
184 } else {
185 conversion
186 };
187 writeln!(out, " {conversion},").ok();
188 }
189
190 writeln!(out, " }}").ok();
191 writeln!(out, " }}").ok();
192 write!(out, "}}").ok();
193 out
194}
195
196pub fn field_conversion_from_core(
199 name: &str,
200 ty: &TypeRef,
201 optional: bool,
202 sanitized: bool,
203 opaque_types: &AHashSet<String>,
204) -> String {
205 if sanitized {
209 if let TypeRef::Vec(inner) = ty {
212 if matches!(inner.as_ref(), TypeRef::Primitive(_)) {
213 if optional {
214 return format!(
215 "{name}: val.{name}.map(|t| {{ let arr: Vec<_> = [t.0, t.1].into_iter().map(|v| v as _).collect(); arr }})"
216 );
217 }
218 return format!("{name}: vec![val.{name}.0 as _, val.{name}.1 as _]");
219 }
220 }
221 if let TypeRef::Optional(opt_inner) = ty {
223 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
224 if matches!(vec_inner.as_ref(), TypeRef::Primitive(_)) {
225 return format!("{name}: val.{name}.map(|t| vec![t.0 as _, t.1 as _])");
226 }
227 }
228 }
229 if let TypeRef::Map(k, v) = ty {
231 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
232 if optional {
233 return format!(
234 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
235 );
236 }
237 return format!(
238 "{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()"
239 );
240 }
241 }
242 if let TypeRef::Vec(inner) = ty {
245 if matches!(inner.as_ref(), TypeRef::String) {
246 if optional {
247 return format!(
248 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
249 );
250 }
251 return format!("{name}: val.{name}.iter().map(|i| format!(\"{{:?}}\", i)).collect()");
252 }
253 }
254 if let TypeRef::Optional(opt_inner) = ty {
256 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
257 if matches!(vec_inner.as_ref(), TypeRef::String) {
258 return format!(
259 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
260 );
261 }
262 }
263 }
264 if matches!(ty, TypeRef::String) {
269 if optional {
270 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
271 }
272 return format!("{name}: format!(\"{{:?}}\", val.{name})");
273 }
274 if optional {
277 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
278 }
279 return format!("{name}: format!(\"{{:?}}\", val.{name})");
280 }
281 match ty {
282 TypeRef::Duration => {
284 if optional {
285 return format!("{name}: val.{name}.map(|d| d.as_millis() as u64)");
286 }
287 format!("{name}: val.{name}.as_millis() as u64")
288 }
289 TypeRef::Path => {
291 if optional {
292 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
293 } else {
294 format!("{name}: val.{name}.to_string_lossy().to_string()")
295 }
296 }
297 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
298 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
299 }
300 TypeRef::Char => {
302 if optional {
303 format!("{name}: val.{name}.map(|c| c.to_string())")
304 } else {
305 format!("{name}: val.{name}.to_string()")
306 }
307 }
308 TypeRef::Bytes => {
310 if optional {
311 format!("{name}: val.{name}.map(|v| v.to_vec())")
312 } else {
313 format!("{name}: val.{name}.to_vec()")
314 }
315 }
316 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
318 if optional {
319 format!("{name}: val.{name}.map(|v| {n} {{ inner: Arc::new(v) }})")
320 } else {
321 format!("{name}: {n} {{ inner: Arc::new(val.{name}) }}")
322 }
323 }
324 TypeRef::Json => {
326 if optional {
327 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
328 } else {
329 format!("{name}: val.{name}.to_string()")
330 }
331 }
332 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
333 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
334 }
335 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
336 if optional {
337 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.to_string()).collect())")
338 } else {
339 format!("{name}: val.{name}.iter().map(ToString::to_string).collect()")
340 }
341 }
342 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Optional(oi) if matches!(oi.as_ref(), TypeRef::Json)) => {
344 if optional {
345 format!(
346 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.as_ref().map(ToString::to_string)).collect())"
347 )
348 } else {
349 format!("{name}: val.{name}.iter().map(|i| i.as_ref().map(ToString::to_string)).collect()")
350 }
351 }
352 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Json) => {
357 if optional {
358 format!(
359 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
360 )
361 } else {
362 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()")
363 }
364 }
365 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
367 if optional {
368 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect())")
369 } else {
370 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v)).collect()")
371 }
372 }
373 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_)) => {
375 if optional {
376 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
377 } else {
378 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.into())).collect()")
379 }
380 }
381 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Named(_))) =>
383 {
384 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
385 }
386 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(_)) => {
388 if optional {
389 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
390 } else {
391 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
392 }
393 }
394 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_))) =>
396 {
397 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
398 }
399 _ => field_conversion_to_core(name, ty, optional),
401 }
402}
403
404pub fn field_conversion_from_core_cfg(
406 name: &str,
407 ty: &TypeRef,
408 optional: bool,
409 sanitized: bool,
410 opaque_types: &AHashSet<String>,
411 config: &ConversionConfig,
412) -> String {
413 if sanitized {
418 if config.map_uses_jsvalue {
419 if let TypeRef::Map(k, v) = ty {
421 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
422 if optional {
423 return format!(
424 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
425 );
426 }
427 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
428 }
429 }
430 if let TypeRef::Vec(inner) = ty {
432 if matches!(inner.as_ref(), TypeRef::Json) {
433 if optional {
434 return format!(
435 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
436 );
437 }
438 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
439 }
440 }
441 }
442 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
443 }
444
445 if config.vec_named_to_string {
449 if let TypeRef::Vec(inner) = ty {
450 if matches!(inner.as_ref(), TypeRef::Named(_)) {
451 if optional {
452 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok())");
453 }
454 return format!("{name}: serde_json::to_string(&val.{name}).unwrap_or_default()");
455 }
456 }
457 }
458
459 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
462 if optional {
463 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
464 }
465 return format!("{name}: format!(\"{{:?}}\", val.{name})");
466 }
467 if config.map_as_string {
468 if let TypeRef::Optional(inner) = ty {
469 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
470 return format!("{name}: val.{name}.as_ref().map(|m| format!(\"{{m:?}}\"))");
471 }
472 }
473 }
474
475 if config.map_uses_jsvalue {
477 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
478 let is_map = matches!(ty, TypeRef::Map(_, _));
479 if is_nested_vec || is_map {
480 if optional {
481 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
482 }
483 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
484 }
485 if let TypeRef::Optional(inner) = ty {
486 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
487 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
488 if is_inner_nested || is_inner_map {
489 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
490 }
491 }
492 }
493
494 let prefix = config.type_name_prefix;
495 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
496
497 match ty {
498 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
500 let cast_to = binding_prim_str(p);
501 if optional {
502 format!("{name}: val.{name}.map(|v| v as {cast_to})")
503 } else {
504 format!("{name}: val.{name} as {cast_to}")
505 }
506 }
507 TypeRef::Optional(inner)
509 if config.cast_large_ints_to_i64
510 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
511 {
512 if let TypeRef::Primitive(p) = inner.as_ref() {
513 let cast_to = binding_prim_str(p);
514 format!("{name}: val.{name}.map(|v| v as {cast_to})")
515 } else {
516 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
517 }
518 }
519 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
521 if optional {
522 format!("{name}: val.{name}.map(|v| v as f64)")
523 } else {
524 format!("{name}: val.{name} as f64")
525 }
526 }
527 TypeRef::Duration if config.cast_large_ints_to_i64 => {
529 if optional {
530 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
531 } else {
532 format!("{name}: val.{name}.as_millis() as u64 as i64")
533 }
534 }
535 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
537 let prefixed = format!("{prefix}{n}");
538 if optional {
539 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
540 } else {
541 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
542 }
543 }
544 TypeRef::Named(n) if is_enum_string(n) => {
546 if optional {
549 format!(
550 "{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())"
551 )
552 } else {
553 format!(
554 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
555 )
556 }
557 }
558 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
560 if optional {
561 format!(
562 "{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())"
563 )
564 } else {
565 format!(
566 "{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()"
567 )
568 }
569 }
570 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
572 {
573 format!(
574 "{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())"
575 )
576 }
577 TypeRef::Vec(inner)
579 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
580 {
581 if optional {
582 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
583 } else {
584 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
585 }
586 }
587 TypeRef::Optional(inner)
589 if config.cast_f32_to_f64
590 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
591 {
592 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
593 }
594 TypeRef::Optional(inner)
596 if config.cast_large_ints_to_i64
597 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
598 {
599 if let TypeRef::Vec(vi) = inner.as_ref() {
600 if let TypeRef::Primitive(p) = vi.as_ref() {
601 let cast_to = binding_prim_str(p);
602 if sanitized {
603 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
605 } else {
606 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
607 }
608 } else {
609 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
610 }
611 } else {
612 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
613 }
614 }
615 TypeRef::Vec(outer)
617 if config.cast_f32_to_f64
618 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
619 {
620 if optional {
621 format!(
622 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
623 )
624 } else {
625 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
626 }
627 }
628 TypeRef::Optional(inner)
630 if config.cast_f32_to_f64
631 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
632 {
633 format!(
634 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
635 )
636 }
637 TypeRef::Optional(inner)
639 if config.cast_large_ints_to_i64
640 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
641 {
642 if let TypeRef::Primitive(p) = inner.as_ref() {
643 let cast_to = binding_prim_str(p);
644 format!("{name}: val.{name}.map(|v| v as {cast_to})")
645 } else {
646 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
647 }
648 }
649 TypeRef::Map(_k, v)
651 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
652 {
653 if let TypeRef::Primitive(p) = v.as_ref() {
654 let cast_to = binding_prim_str(p);
655 if optional {
656 format!(
657 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
658 )
659 } else {
660 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
661 }
662 } else {
663 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
664 }
665 }
666 TypeRef::Vec(inner)
668 if config.cast_large_ints_to_i64
669 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
670 {
671 if let TypeRef::Primitive(p) = inner.as_ref() {
672 let cast_to = binding_prim_str(p);
673 if sanitized {
674 if optional {
676 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
677 } else {
678 format!("{name}: {{ let (a, b) = val.{name}; vec![a as {cast_to}, b as {cast_to}] }}")
679 }
680 } else if optional {
681 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
682 } else {
683 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
684 }
685 } else {
686 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
687 }
688 }
689 TypeRef::Vec(outer)
691 if config.cast_large_ints_to_i64
692 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
693 {
694 if let TypeRef::Vec(inner) = outer.as_ref() {
695 if let TypeRef::Primitive(p) = inner.as_ref() {
696 let cast_to = binding_prim_str(p);
697 if optional {
698 format!(
699 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
700 )
701 } else {
702 format!(
703 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
704 )
705 }
706 } else {
707 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
708 }
709 } else {
710 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
711 }
712 }
713 TypeRef::Json if config.json_to_string => {
715 if optional {
716 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
717 } else {
718 format!("{name}: val.{name}.to_string()")
719 }
720 }
721 TypeRef::Json if config.map_uses_jsvalue => {
723 if optional {
724 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
725 } else {
726 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
727 }
728 }
729 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
731 if optional {
732 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
733 } else {
734 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
735 }
736 }
737 TypeRef::Optional(inner)
739 if config.map_uses_jsvalue
740 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
741 {
742 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
743 }
744 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
746 }
747}
748
749fn apply_core_wrapper_from_core(
752 conversion: &str,
753 name: &str,
754 core_wrapper: &CoreWrapper,
755 vec_inner_core_wrapper: &CoreWrapper,
756 optional: bool,
757) -> String {
758 if *vec_inner_core_wrapper == CoreWrapper::Arc {
760 return conversion
761 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
762 .replace(
763 "map(|v| v.into_iter().map(Into::into)",
764 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
765 );
766 }
767
768 match core_wrapper {
769 CoreWrapper::None => conversion.to_string(),
770 CoreWrapper::Cow => {
771 let prefix = format!("{name}: ");
778 let already_some_wrapped = conversion
779 .strip_prefix(&prefix)
780 .is_some_and(|expr| expr.starts_with("Some("));
781 if optional {
782 format!("{name}: val.{name}.as_ref().map(|v| v.to_string())")
783 } else if already_some_wrapped {
784 format!("{name}: Some(val.{name}.to_string())")
785 } else {
786 format!("{name}: val.{name}.to_string()")
787 }
788 }
789 CoreWrapper::Arc => {
790 if conversion.contains("{ inner: Arc::new(") {
799 return conversion.replace("{ inner: Arc::new(v) }", "{ inner: v }").replace(
800 &format!("{{ inner: Arc::new(val.{name}) }}"),
801 &format!("{{ inner: val.{name} }}"),
802 );
803 }
804 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
805 if optional {
806 format!("{name}: {expr}.map(|v| (*v).clone().into())")
807 } else {
808 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
809 format!("{name}: {unwrapped}")
810 }
811 } else {
812 conversion.to_string()
813 }
814 }
815 CoreWrapper::Bytes => {
816 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
818 if optional {
819 format!("{name}: {expr}.map(|v| v.to_vec())")
820 } else if expr == format!("val.{name}") {
821 format!("{name}: val.{name}.to_vec()")
822 } else {
823 conversion.to_string()
824 }
825 } else {
826 conversion.to_string()
827 }
828 }
829 CoreWrapper::ArcMutex => {
830 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
832 if optional {
833 format!("{name}: {expr}.map(|v| v.lock().unwrap().clone().into())")
834 } else if expr == format!("val.{name}") {
835 format!("{name}: val.{name}.lock().unwrap().clone().into()")
836 } else {
837 conversion.to_string()
838 }
839 } else {
840 conversion.to_string()
841 }
842 }
843 }
844}