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, 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(typ, core_import);
23 let binding_name = format!("{}{}", config.type_name_prefix, typ.name);
24 let mut out = String::with_capacity(256);
25 writeln!(out, "impl From<{core_path}> for {binding_name} {{").ok();
26 writeln!(out, " fn from(val: {core_path}) -> Self {{").ok();
27
28 if is_newtype(typ) {
30 let field = &typ.fields[0];
31 let inner_expr = match &field.ty {
32 TypeRef::Named(_) => "val.0.into()".to_string(),
33 TypeRef::Path => "val.0.to_string_lossy().to_string()".to_string(),
34 TypeRef::Duration => "val.0.as_millis() as u64".to_string(),
35 _ => "val.0".to_string(),
36 };
37 writeln!(out, " Self {{ _0: {inner_expr} }}").ok();
38 writeln!(out, " }}").ok();
39 write!(out, "}}").ok();
40 return out;
41 }
42
43 let optionalized = config.optionalize_defaults && typ.has_default;
44 writeln!(out, " Self {{").ok();
45 for field in &typ.fields {
46 if !config.exclude_types.is_empty()
48 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types)
49 {
50 continue;
51 }
52 let base_conversion = field_conversion_from_core_cfg(
53 &field.name,
54 &field.ty,
55 field.optional,
56 field.sanitized,
57 opaque_types,
58 config,
59 );
60 let base_conversion = if field.is_boxed && matches!(&field.ty, TypeRef::Named(_)) {
62 if field.optional {
63 let src = format!("{}: val.{}.map(Into::into)", field.name, field.name);
65 let dst = format!("{}: val.{}.map(|v| (*v).into())", field.name, field.name);
66 if base_conversion == src { dst } else { base_conversion }
67 } else {
68 base_conversion.replace(&format!("val.{}", field.name), &format!("(*val.{})", field.name))
70 }
71 } else {
72 base_conversion
73 };
74 let base_conversion = if field.newtype_wrapper.is_some() {
80 match &field.ty {
81 TypeRef::Optional(_) => {
82 base_conversion.replace(
84 &format!("val.{}", field.name),
85 &format!("val.{}.map(|v| v.0)", field.name),
86 )
87 }
88 TypeRef::Vec(_) => {
89 base_conversion.replace(
91 &format!("val.{}", field.name),
92 &format!("val.{}.iter().map(|v| v.0).collect::<Vec<_>>()", field.name),
93 )
94 }
95 _ if field.optional => base_conversion.replace(
98 &format!("val.{}", field.name),
99 &format!("val.{}.map(|v| v.0)", field.name),
100 ),
101 _ => {
102 base_conversion.replace(&format!("val.{}", field.name), &format!("val.{}.0", field.name))
104 }
105 }
106 } else {
107 base_conversion
108 };
109 let is_flattened_optional = field.optional && matches!(field.ty, TypeRef::Optional(_));
115 let base_conversion = if is_flattened_optional {
116 if let TypeRef::Optional(inner) = &field.ty {
117 let inner_conv = field_conversion_from_core_cfg(
119 &field.name,
120 inner.as_ref(),
121 true,
122 field.sanitized,
123 opaque_types,
124 config,
125 );
126 inner_conv.replace(&format!("val.{}", field.name), &format!("val.{}.flatten()", field.name))
128 } else {
129 base_conversion
130 }
131 } else {
132 base_conversion
133 };
134 let needs_some_wrap = !is_flattened_optional
138 && ((optionalized && !field.optional)
139 || (config.option_duration_on_defaults
140 && typ.has_default
141 && !field.optional
142 && matches!(field.ty, TypeRef::Duration)));
143 let conversion = if needs_some_wrap {
144 if let Some(expr) = base_conversion.strip_prefix(&format!("{}: ", field.name)) {
146 format!("{}: Some({})", field.name, expr)
147 } else {
148 base_conversion
149 }
150 } else {
151 base_conversion
152 };
153 let conversion = if !field.sanitized {
156 apply_core_wrapper_from_core(
157 &conversion,
158 &field.name,
159 &field.core_wrapper,
160 &field.vec_inner_core_wrapper,
161 field.optional,
162 )
163 } else {
164 conversion
165 };
166 if field.cfg.is_some() {
168 continue;
169 }
170 let binding_field = config.binding_field_name_owned(&typ.name, &field.name);
174 let conversion = if binding_field != field.name {
175 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
176 format!("{binding_field}: {expr}")
177 } else {
178 conversion
179 }
180 } else {
181 conversion
182 };
183 writeln!(out, " {conversion},").ok();
184 }
185
186 writeln!(out, " }}").ok();
187 writeln!(out, " }}").ok();
188 write!(out, "}}").ok();
189 out
190}
191
192pub fn field_conversion_from_core(
195 name: &str,
196 ty: &TypeRef,
197 optional: bool,
198 sanitized: bool,
199 opaque_types: &AHashSet<String>,
200) -> String {
201 if sanitized {
205 if let TypeRef::Vec(inner) = ty {
208 if matches!(inner.as_ref(), TypeRef::Primitive(_)) {
209 if optional {
210 return format!(
211 "{name}: val.{name}.map(|t| {{ let arr: Vec<_> = [t.0, t.1].into_iter().map(|v| v as _).collect(); arr }})"
212 );
213 }
214 return format!("{name}: vec![val.{name}.0 as _, val.{name}.1 as _]");
215 }
216 }
217 if let TypeRef::Optional(opt_inner) = ty {
219 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
220 if matches!(vec_inner.as_ref(), TypeRef::Primitive(_)) {
221 return format!("{name}: val.{name}.map(|t| vec![t.0 as _, t.1 as _])");
222 }
223 }
224 }
225 if let TypeRef::Map(k, v) = ty {
227 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
228 if optional {
229 return format!(
230 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect())"
231 );
232 }
233 return format!(
234 "{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()"
235 );
236 }
237 }
238 if let TypeRef::Vec(inner) = ty {
241 if matches!(inner.as_ref(), TypeRef::String) {
242 if optional {
243 return format!(
244 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
245 );
246 }
247 return format!("{name}: val.{name}.iter().map(|i| format!(\"{{:?}}\", i)).collect()");
248 }
249 }
250 if let TypeRef::Optional(opt_inner) = ty {
252 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
253 if matches!(vec_inner.as_ref(), TypeRef::String) {
254 return format!(
255 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
256 );
257 }
258 }
259 }
260 if matches!(ty, TypeRef::String) {
264 if optional {
265 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
266 }
267 return format!("{name}: format!(\"{{:?}}\", val.{name})");
268 }
269 if optional {
272 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{v:?}}\"))");
273 }
274 return format!("{name}: format!(\"{{:?}}\", val.{name})");
275 }
276 match ty {
277 TypeRef::Duration => {
279 if optional {
280 return format!("{name}: val.{name}.map(|d| d.as_millis() as u64)");
281 }
282 format!("{name}: val.{name}.as_millis() as u64")
283 }
284 TypeRef::Path => {
286 if optional {
287 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
288 } else {
289 format!("{name}: val.{name}.to_string_lossy().to_string()")
290 }
291 }
292 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
293 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
294 }
295 TypeRef::Char => {
297 if optional {
298 format!("{name}: val.{name}.map(|c| c.to_string())")
299 } else {
300 format!("{name}: val.{name}.to_string()")
301 }
302 }
303 TypeRef::Bytes => {
305 if optional {
306 format!("{name}: val.{name}.map(|v| v.to_vec())")
307 } else {
308 format!("{name}: val.{name}.to_vec()")
309 }
310 }
311 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
313 if optional {
314 format!("{name}: val.{name}.map(|v| {n} {{ inner: Arc::new(v) }})")
315 } else {
316 format!("{name}: {n} {{ inner: Arc::new(val.{name}) }}")
317 }
318 }
319 TypeRef::Json => {
321 if optional {
322 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
323 } else {
324 format!("{name}: val.{name}.to_string()")
325 }
326 }
327 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
328 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
329 }
330 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
331 if optional {
332 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.to_string()).collect())")
333 } else {
334 format!("{name}: val.{name}.iter().map(ToString::to_string).collect()")
335 }
336 }
337 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Optional(oi) if matches!(oi.as_ref(), TypeRef::Json)) => {
339 if optional {
340 format!(
341 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.as_ref().map(ToString::to_string)).collect())"
342 )
343 } else {
344 format!("{name}: val.{name}.iter().map(|i| i.as_ref().map(ToString::to_string)).collect()")
345 }
346 }
347 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
349 let k_is_json = matches!(k.as_ref(), TypeRef::Json);
350 let k_expr = if k_is_json { "k.to_string()" } else { "k" };
351 if optional {
352 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, v.to_string())).collect())")
353 } else {
354 format!("{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, v.to_string())).collect()")
355 }
356 }
357 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
359 if optional {
360 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect())")
361 } else {
362 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v)).collect()")
363 }
364 }
365 _ => field_conversion_to_core(name, ty, optional),
367 }
368}
369
370pub fn field_conversion_from_core_cfg(
372 name: &str,
373 ty: &TypeRef,
374 optional: bool,
375 sanitized: bool,
376 opaque_types: &AHashSet<String>,
377 config: &ConversionConfig,
378) -> String {
379 if sanitized {
384 if config.map_uses_jsvalue {
385 if let TypeRef::Map(k, v) = ty {
387 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
388 if optional {
389 return format!(
390 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
391 );
392 }
393 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
394 }
395 }
396 if let TypeRef::Vec(inner) = ty {
398 if matches!(inner.as_ref(), TypeRef::Json) {
399 if optional {
400 return format!(
401 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
402 );
403 }
404 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
405 }
406 }
407 }
408 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
409 }
410
411 if config.vec_named_to_string {
415 if let TypeRef::Vec(inner) = ty {
416 if matches!(inner.as_ref(), TypeRef::Named(_)) {
417 if optional {
418 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_json::to_string(v).ok())");
419 }
420 return format!("{name}: serde_json::to_string(&val.{name}).unwrap_or_default()");
421 }
422 }
423 }
424
425 if config.map_uses_jsvalue {
427 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
428 let is_map = matches!(ty, TypeRef::Map(_, _));
429 if is_nested_vec || is_map {
430 if optional {
431 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
432 }
433 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
434 }
435 if let TypeRef::Optional(inner) = ty {
436 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
437 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
438 if is_inner_nested || is_inner_map {
439 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
440 }
441 }
442 }
443
444 let prefix = config.type_name_prefix;
445 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
446
447 match ty {
448 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
450 let cast_to = binding_prim_str(p);
451 if optional {
452 format!("{name}: val.{name}.map(|v| v as {cast_to})")
453 } else {
454 format!("{name}: val.{name} as {cast_to}")
455 }
456 }
457 TypeRef::Optional(inner)
459 if config.cast_large_ints_to_i64
460 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
461 {
462 if let TypeRef::Primitive(p) = inner.as_ref() {
463 let cast_to = binding_prim_str(p);
464 format!("{name}: val.{name}.map(|v| v as {cast_to})")
465 } else {
466 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
467 }
468 }
469 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
471 if optional {
472 format!("{name}: val.{name}.map(|v| v as f64)")
473 } else {
474 format!("{name}: val.{name} as f64")
475 }
476 }
477 TypeRef::Duration if config.cast_large_ints_to_i64 => {
479 if optional {
480 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
481 } else {
482 format!("{name}: val.{name}.as_millis() as u64 as i64")
483 }
484 }
485 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
487 let prefixed = format!("{prefix}{n}");
488 if optional {
489 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
490 } else {
491 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
492 }
493 }
494 TypeRef::Named(n) if is_enum_string(n) => {
496 if optional {
499 format!(
500 "{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())"
501 )
502 } else {
503 format!(
504 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
505 )
506 }
507 }
508 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
510 if optional {
511 format!(
512 "{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())"
513 )
514 } else {
515 format!(
516 "{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()"
517 )
518 }
519 }
520 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
522 {
523 format!(
524 "{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())"
525 )
526 }
527 TypeRef::Vec(inner)
529 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
530 {
531 if optional {
532 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
533 } else {
534 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
535 }
536 }
537 TypeRef::Optional(inner)
539 if config.cast_f32_to_f64
540 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
541 {
542 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
543 }
544 TypeRef::Optional(inner)
546 if config.cast_large_ints_to_i64
547 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
548 {
549 if let TypeRef::Vec(vi) = inner.as_ref() {
550 if let TypeRef::Primitive(p) = vi.as_ref() {
551 let cast_to = binding_prim_str(p);
552 if sanitized {
553 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
555 } else {
556 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
557 }
558 } else {
559 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
560 }
561 } else {
562 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
563 }
564 }
565 TypeRef::Vec(outer)
567 if config.cast_f32_to_f64
568 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
569 {
570 if optional {
571 format!(
572 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
573 )
574 } else {
575 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
576 }
577 }
578 TypeRef::Optional(inner)
580 if config.cast_f32_to_f64
581 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
582 {
583 format!(
584 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
585 )
586 }
587 TypeRef::Optional(inner)
589 if config.cast_large_ints_to_i64
590 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
591 {
592 if let TypeRef::Primitive(p) = inner.as_ref() {
593 let cast_to = binding_prim_str(p);
594 format!("{name}: val.{name}.map(|v| v as {cast_to})")
595 } else {
596 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
597 }
598 }
599 TypeRef::Map(_k, v)
601 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
602 {
603 if let TypeRef::Primitive(p) = v.as_ref() {
604 let cast_to = binding_prim_str(p);
605 if optional {
606 format!(
607 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
608 )
609 } else {
610 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
611 }
612 } else {
613 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
614 }
615 }
616 TypeRef::Vec(inner)
618 if config.cast_large_ints_to_i64
619 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
620 {
621 if let TypeRef::Primitive(p) = inner.as_ref() {
622 let cast_to = binding_prim_str(p);
623 if sanitized {
624 if optional {
626 format!("{name}: val.{name}.map(|(a, b)| vec![a as {cast_to}, b as {cast_to}])")
627 } else {
628 format!("{name}: {{ let (a, b) = val.{name}; vec![a as {cast_to}, b as {cast_to}] }}")
629 }
630 } else if optional {
631 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
632 } else {
633 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
634 }
635 } else {
636 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
637 }
638 }
639 TypeRef::Vec(outer)
641 if config.cast_large_ints_to_i64
642 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
643 {
644 if let TypeRef::Vec(inner) = outer.as_ref() {
645 if let TypeRef::Primitive(p) = inner.as_ref() {
646 let cast_to = binding_prim_str(p);
647 if optional {
648 format!(
649 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
650 )
651 } else {
652 format!(
653 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
654 )
655 }
656 } else {
657 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
658 }
659 } else {
660 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
661 }
662 }
663 TypeRef::Json if config.json_to_string => {
665 if optional {
666 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
667 } else {
668 format!("{name}: val.{name}.to_string()")
669 }
670 }
671 TypeRef::Json if config.map_uses_jsvalue => {
673 if optional {
674 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
675 } else {
676 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
677 }
678 }
679 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
681 if optional {
682 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
683 } else {
684 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
685 }
686 }
687 TypeRef::Optional(inner)
689 if config.map_uses_jsvalue
690 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
691 {
692 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
693 }
694 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
696 }
697}
698
699fn apply_core_wrapper_from_core(
702 conversion: &str,
703 name: &str,
704 core_wrapper: &CoreWrapper,
705 vec_inner_core_wrapper: &CoreWrapper,
706 optional: bool,
707) -> String {
708 if *vec_inner_core_wrapper == CoreWrapper::Arc {
710 return conversion
711 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
712 .replace(
713 "map(|v| v.into_iter().map(Into::into)",
714 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
715 );
716 }
717
718 match core_wrapper {
719 CoreWrapper::None => conversion.to_string(),
720 CoreWrapper::Cow => {
721 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
726 if optional {
727 conversion.to_string()
729 } else if expr == format!("val.{name}") {
730 format!("{name}: val.{name}.into_owned()")
731 } else {
732 conversion.to_string()
733 }
734 } else {
735 conversion.to_string()
736 }
737 }
738 CoreWrapper::Arc => {
739 if conversion.contains("{ inner: Arc::new(") {
748 return conversion.replace("{ inner: Arc::new(v) }", "{ inner: v }").replace(
749 &format!("{{ inner: Arc::new(val.{name}) }}"),
750 &format!("{{ inner: val.{name} }}"),
751 );
752 }
753 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
754 if optional {
755 format!("{name}: {expr}.map(|v| (*v).clone().into())")
756 } else {
757 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
758 format!("{name}: {unwrapped}")
759 }
760 } else {
761 conversion.to_string()
762 }
763 }
764 CoreWrapper::Bytes => {
765 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
767 if optional {
768 format!("{name}: {expr}.map(|v| v.to_vec())")
769 } else if expr == format!("val.{name}") {
770 format!("{name}: val.{name}.to_vec()")
771 } else {
772 conversion.to_string()
773 }
774 } else {
775 conversion.to_string()
776 }
777 }
778 CoreWrapper::ArcMutex => {
779 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
781 if optional {
782 format!("{name}: {expr}.map(|v| v.lock().unwrap().clone().into())")
783 } else if expr == format!("val.{name}") {
784 format!("{name}: val.{name}.lock().unwrap().clone().into()")
785 } else {
786 conversion.to_string()
787 }
788 } else {
789 conversion.to_string()
790 }
791 }
792 }
793}