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 writeln!(out, " {conversion},").ok();
171 }
172
173 writeln!(out, " }}").ok();
174 writeln!(out, " }}").ok();
175 write!(out, "}}").ok();
176 out
177}
178
179pub fn field_conversion_from_core(
182 name: &str,
183 ty: &TypeRef,
184 optional: bool,
185 sanitized: bool,
186 opaque_types: &AHashSet<String>,
187) -> String {
188 if sanitized {
191 if let TypeRef::Map(k, v) = ty {
193 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
194 if optional {
195 return format!(
196 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (format!(\"{{:?}}\", k), format!(\"{{:?}}\", v))).collect())"
197 );
198 }
199 return format!(
200 "{name}: val.{name}.into_iter().map(|(k, v)| (format!(\"{{:?}}\", k), format!(\"{{:?}}\", v))).collect()"
201 );
202 }
203 }
204 if let TypeRef::Vec(inner) = ty {
206 if matches!(inner.as_ref(), TypeRef::String) {
207 if optional {
208 return format!(
209 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
210 );
211 }
212 return format!("{name}: val.{name}.iter().map(|i| format!(\"{{:?}}\", i)).collect()");
213 }
214 }
215 if let TypeRef::Optional(opt_inner) = ty {
218 if let TypeRef::Vec(vec_inner) = opt_inner.as_ref() {
219 if matches!(vec_inner.as_ref(), TypeRef::String) {
220 return format!(
221 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| format!(\"{{:?}}\", i)).collect())"
222 );
223 }
224 }
225 }
226 if matches!(ty, TypeRef::String) {
229 if optional {
230 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{:?}}\", v))");
231 }
232 return format!("{name}: format!(\"{{:?}}\", val.{name})");
233 }
234 if optional {
236 return format!("{name}: val.{name}.as_ref().map(|v| format!(\"{{:?}}\", v))");
237 }
238 return format!("{name}: format!(\"{{:?}}\", val.{name})");
239 }
240 match ty {
241 TypeRef::Duration => {
243 if optional {
244 return format!("{name}: val.{name}.map(|d| d.as_millis() as u64)");
245 }
246 format!("{name}: val.{name}.as_millis() as u64")
247 }
248 TypeRef::Path => {
250 if optional {
251 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
252 } else {
253 format!("{name}: val.{name}.to_string_lossy().to_string()")
254 }
255 }
256 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
257 format!("{name}: val.{name}.map(|p| p.to_string_lossy().to_string())")
258 }
259 TypeRef::Char => {
261 if optional {
262 format!("{name}: val.{name}.map(|c| c.to_string())")
263 } else {
264 format!("{name}: val.{name}.to_string()")
265 }
266 }
267 TypeRef::Bytes => {
269 if optional {
270 format!("{name}: val.{name}.map(|v| v.to_vec())")
271 } else {
272 format!("{name}: val.{name}.to_vec()")
273 }
274 }
275 TypeRef::Named(n) if opaque_types.contains(n.as_str()) => {
277 if optional {
278 format!("{name}: val.{name}.map(|v| {n} {{ inner: Arc::new(v) }})")
279 } else {
280 format!("{name}: {n} {{ inner: Arc::new(val.{name}) }}")
281 }
282 }
283 TypeRef::Json => {
285 if optional {
286 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
287 } else {
288 format!("{name}: val.{name}.to_string()")
289 }
290 }
291 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
292 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
293 }
294 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json) => {
295 if optional {
296 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.to_string()).collect())")
297 } else {
298 format!("{name}: val.{name}.iter().map(ToString::to_string).collect()")
299 }
300 }
301 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Optional(oi) if matches!(oi.as_ref(), TypeRef::Json)) => {
303 if optional {
304 format!(
305 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|i| i.as_ref().map(ToString::to_string)).collect())"
306 )
307 } else {
308 format!("{name}: val.{name}.iter().map(|i| i.as_ref().map(ToString::to_string)).collect()")
309 }
310 }
311 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
313 let k_is_json = matches!(k.as_ref(), TypeRef::Json);
314 let k_expr = if k_is_json { "k.to_string()" } else { "k" };
315 if optional {
316 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, v.to_string())).collect())")
317 } else {
318 format!("{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, v.to_string())).collect()")
319 }
320 }
321 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
323 if optional {
324 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect())")
325 } else {
326 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.to_string(), v)).collect()")
327 }
328 }
329 _ => field_conversion_to_core(name, ty, optional),
331 }
332}
333
334pub fn field_conversion_from_core_cfg(
336 name: &str,
337 ty: &TypeRef,
338 optional: bool,
339 sanitized: bool,
340 opaque_types: &AHashSet<String>,
341 config: &ConversionConfig,
342) -> String {
343 if sanitized {
348 if config.map_uses_jsvalue {
349 if let TypeRef::Map(k, v) = ty {
351 if matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String) {
352 if optional {
353 return format!(
354 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
355 );
356 }
357 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
358 }
359 }
360 if let TypeRef::Vec(inner) = ty {
362 if matches!(inner.as_ref(), TypeRef::Json) {
363 if optional {
364 return format!(
365 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())"
366 );
367 }
368 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
369 }
370 }
371 }
372 return field_conversion_from_core(name, ty, optional, sanitized, opaque_types);
373 }
374
375 if config.map_uses_jsvalue {
377 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
378 let is_map = matches!(ty, TypeRef::Map(_, _));
379 if is_nested_vec || is_map {
380 if optional {
381 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
382 }
383 return format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)");
384 }
385 if let TypeRef::Optional(inner) = ty {
386 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
387 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
388 if is_inner_nested || is_inner_map {
389 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())");
390 }
391 }
392 }
393
394 let prefix = config.type_name_prefix;
395 let is_enum_string = |n: &str| -> bool { config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)) };
396
397 match ty {
398 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
400 let cast_to = binding_prim_str(p);
401 if optional {
402 format!("{name}: val.{name}.map(|v| v as {cast_to})")
403 } else {
404 format!("{name}: val.{name} as {cast_to}")
405 }
406 }
407 TypeRef::Optional(inner)
409 if config.cast_large_ints_to_i64
410 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
411 {
412 if let TypeRef::Primitive(p) = inner.as_ref() {
413 let cast_to = binding_prim_str(p);
414 format!("{name}: val.{name}.map(|v| v as {cast_to})")
415 } else {
416 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
417 }
418 }
419 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
421 if optional {
422 format!("{name}: val.{name}.map(|v| v as f64)")
423 } else {
424 format!("{name}: val.{name} as f64")
425 }
426 }
427 TypeRef::Duration if config.cast_large_ints_to_i64 => {
429 if optional {
430 format!("{name}: val.{name}.map(|d| d.as_millis() as u64 as i64)")
431 } else {
432 format!("{name}: val.{name}.as_millis() as u64 as i64")
433 }
434 }
435 TypeRef::Named(n) if opaque_types.contains(n.as_str()) && !prefix.is_empty() => {
437 let prefixed = format!("{prefix}{n}");
438 if optional {
439 format!("{name}: val.{name}.map(|v| {prefixed} {{ inner: Arc::new(v) }})")
440 } else {
441 format!("{name}: {prefixed} {{ inner: Arc::new(val.{name}) }}")
442 }
443 }
444 TypeRef::Named(n) if is_enum_string(n) => {
446 if optional {
449 format!(
450 "{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())"
451 )
452 } else {
453 format!(
454 "{name}: serde_json::to_value(val.{name}).ok().and_then(|s| s.as_str().map(String::from)).unwrap_or_default()"
455 )
456 }
457 }
458 TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if is_enum_string(n)) => {
460 if optional {
461 format!(
462 "{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())"
463 )
464 } else {
465 format!(
466 "{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()"
467 )
468 }
469 }
470 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(n) if is_enum_string(n))) =>
472 {
473 format!(
474 "{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())"
475 )
476 }
477 TypeRef::Vec(inner)
479 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
480 {
481 if optional {
482 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
483 } else {
484 format!("{name}: val.{name}.iter().map(|&v| v as f64).collect()")
485 }
486 }
487 TypeRef::Optional(inner)
489 if config.cast_f32_to_f64
490 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
491 {
492 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as f64).collect())")
493 }
494 TypeRef::Vec(outer)
496 if config.cast_f32_to_f64
497 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
498 {
499 if optional {
500 format!(
501 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
502 )
503 } else {
504 format!("{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect()")
505 }
506 }
507 TypeRef::Optional(inner)
509 if config.cast_f32_to_f64
510 && matches!(inner.as_ref(), TypeRef::Vec(outer) if matches!(outer.as_ref(), TypeRef::Vec(prim) if matches!(prim.as_ref(), TypeRef::Primitive(PrimitiveType::F32)))) =>
511 {
512 format!(
513 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as f64).collect()).collect())"
514 )
515 }
516 TypeRef::Optional(inner)
518 if config.cast_large_ints_to_i64
519 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
520 {
521 if let TypeRef::Primitive(p) = inner.as_ref() {
522 let cast_to = binding_prim_str(p);
523 format!("{name}: val.{name}.map(|v| v as {cast_to})")
524 } else {
525 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
526 }
527 }
528 TypeRef::Map(k, v)
530 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
531 {
532 if let TypeRef::Primitive(p) = v.as_ref() {
533 let cast_to = binding_prim_str(p);
534 if optional {
535 format!(
536 "{name}: val.{name}.as_ref().map(|m| m.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect())"
537 )
538 } else {
539 format!("{name}: val.{name}.iter().map(|(k, v)| (k.clone(), *v as {cast_to})).collect()")
540 }
541 } else {
542 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
543 }
544 }
545 TypeRef::Vec(inner)
547 if config.cast_large_ints_to_i64
548 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
549 {
550 if let TypeRef::Primitive(p) = inner.as_ref() {
551 let cast_to = binding_prim_str(p);
552 if optional {
553 format!("{name}: val.{name}.as_ref().map(|v| v.iter().map(|&x| x as {cast_to}).collect())")
554 } else {
555 format!("{name}: val.{name}.iter().map(|&v| v as {cast_to}).collect()")
556 }
557 } else {
558 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
559 }
560 }
561 TypeRef::Vec(outer)
563 if config.cast_large_ints_to_i64
564 && matches!(outer.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p))) =>
565 {
566 if let TypeRef::Vec(inner) = outer.as_ref() {
567 if let TypeRef::Primitive(p) = inner.as_ref() {
568 let cast_to = binding_prim_str(p);
569 if optional {
570 format!(
571 "{name}: val.{name}.as_ref().map(|v| v.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect())"
572 )
573 } else {
574 format!(
575 "{name}: val.{name}.iter().map(|inner| inner.iter().map(|&x| x as {cast_to}).collect()).collect()"
576 )
577 }
578 } else {
579 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
580 }
581 } else {
582 field_conversion_from_core(name, ty, optional, sanitized, opaque_types)
583 }
584 }
585 TypeRef::Json if config.json_to_string => {
587 if optional {
588 format!("{name}: val.{name}.as_ref().map(ToString::to_string)")
589 } else {
590 format!("{name}: val.{name}.to_string()")
591 }
592 }
593 TypeRef::Json if config.map_uses_jsvalue => {
595 if optional {
596 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
597 } else {
598 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
599 }
600 }
601 TypeRef::Vec(inner) if config.map_uses_jsvalue && matches!(inner.as_ref(), TypeRef::Json) => {
603 if optional {
604 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
605 } else {
606 format!("{name}: serde_wasm_bindgen::to_value(&val.{name}).unwrap_or(JsValue::NULL)")
607 }
608 }
609 TypeRef::Optional(inner)
611 if config.map_uses_jsvalue
612 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json)) =>
613 {
614 format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::to_value(v).ok())")
615 }
616 _ => field_conversion_from_core(name, ty, optional, sanitized, opaque_types),
618 }
619}
620
621fn apply_core_wrapper_from_core(
624 conversion: &str,
625 name: &str,
626 core_wrapper: &CoreWrapper,
627 vec_inner_core_wrapper: &CoreWrapper,
628 optional: bool,
629) -> String {
630 if *vec_inner_core_wrapper == CoreWrapper::Arc {
632 return conversion
633 .replace(".map(Into::into).collect()", ".map(|v| (*v).clone().into()).collect()")
634 .replace(
635 "map(|v| v.into_iter().map(Into::into)",
636 "map(|v| v.into_iter().map(|v| (*v).clone().into())",
637 );
638 }
639
640 match core_wrapper {
641 CoreWrapper::None => conversion.to_string(),
642 CoreWrapper::Cow => {
643 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
648 if optional {
649 conversion.to_string()
651 } else if expr == format!("val.{name}") {
652 format!("{name}: val.{name}.into_owned()")
653 } else {
654 conversion.to_string()
655 }
656 } else {
657 conversion.to_string()
658 }
659 }
660 CoreWrapper::Arc => {
661 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
663 if optional {
664 format!("{name}: {expr}.map(|v| (*v).clone().into())")
665 } else {
666 let unwrapped = expr.replace(&format!("val.{name}"), &format!("(*val.{name}).clone()"));
667 format!("{name}: {unwrapped}")
668 }
669 } else {
670 conversion.to_string()
671 }
672 }
673 CoreWrapper::Bytes => {
674 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
676 if optional {
677 format!("{name}: {expr}.map(|v| v.to_vec())")
678 } else if expr == format!("val.{name}") {
679 format!("{name}: val.{name}.to_vec()")
680 } else {
681 conversion.to_string()
682 }
683 } else {
684 conversion.to_string()
685 }
686 }
687 }
688}