1use alef_core::ir::{CoreWrapper, PrimitiveType, TypeDef, TypeRef};
2use std::fmt::Write;
3
4use super::ConversionConfig;
5use super::helpers::{
6 core_prim_str, core_type_path_remapped, is_newtype, is_tuple_type_name, needs_f64_cast, needs_i32_cast,
7 needs_i64_cast,
8};
9
10pub fn gen_from_binding_to_core(typ: &TypeDef, core_import: &str) -> String {
14 gen_from_binding_to_core_cfg(typ, core_import, &ConversionConfig::default())
15}
16
17pub fn gen_from_binding_to_core_cfg(typ: &TypeDef, core_import: &str, config: &ConversionConfig) -> String {
19 let core_path = core_type_path_remapped(typ, core_import, config.source_crate_remaps);
20 let binding_name = format!("{}{}", config.type_name_prefix, typ.name);
21 let mut out = String::with_capacity(256);
22 if typ.has_stripped_cfg_fields {
25 writeln!(out, "#[allow(clippy::needless_update)]").ok();
26 }
27 let uses_builder_pattern = (config.option_duration_on_defaults
32 && typ.has_default
33 && typ
34 .fields
35 .iter()
36 .any(|f| !f.optional && matches!(f.ty, TypeRef::Duration)))
37 || (config.optionalize_defaults && typ.has_default);
38 if uses_builder_pattern {
39 writeln!(
40 out,
41 "#[allow(clippy::field_reassign_with_default, clippy::let_and_return)]"
42 )
43 .ok();
44 }
45 writeln!(out, "#[allow(clippy::redundant_closure, clippy::useless_conversion)]").ok();
46 writeln!(out, "impl From<{binding_name}> for {core_path} {{").ok();
47 writeln!(out, " fn from(val: {binding_name}) -> Self {{").ok();
48
49 if is_newtype(typ) {
51 let field = &typ.fields[0];
52 let inner_expr = match &field.ty {
53 TypeRef::Named(_) => "val._0.into()".to_string(),
54 TypeRef::Path => "val._0.into()".to_string(),
55 TypeRef::Duration => "std::time::Duration::from_millis(val._0)".to_string(),
56 _ => "val._0".to_string(),
57 };
58 writeln!(out, " Self({inner_expr})").ok();
59 writeln!(out, " }}").ok();
60 write!(out, "}}").ok();
61 return out;
62 }
63
64 let has_optionalized_duration = config.option_duration_on_defaults
69 && typ.has_default
70 && typ
71 .fields
72 .iter()
73 .any(|f| !f.optional && matches!(f.ty, TypeRef::Duration));
74
75 if has_optionalized_duration {
76 writeln!(out, " let mut __result = {core_path}::default();").ok();
78 let optionalized = config.optionalize_defaults && typ.has_default;
79 for field in &typ.fields {
80 if field.cfg.is_some() {
82 continue;
83 }
84 if field.sanitized && field.core_wrapper != CoreWrapper::Cow {
85 continue;
87 }
88 if !config.exclude_types.is_empty()
90 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types)
91 {
92 continue;
93 }
94 let binding_name = config.binding_field_name_owned(&typ.name, &field.name);
96 if !field.optional && matches!(field.ty, TypeRef::Duration) {
97 let cast = if config.cast_large_ints_to_i64 { " as u64" } else { "" };
98 writeln!(
99 out,
100 " if let Some(__v) = val.{binding_name} {{ __result.{} = std::time::Duration::from_millis(__v{cast}); }}",
101 field.name
102 )
103 .ok();
104 continue;
105 }
106 let conversion = if optionalized && !field.optional {
107 gen_optionalized_field_to_core(&field.name, &field.ty, config, false)
108 } else {
109 field_conversion_to_core_cfg(&field.name, &field.ty, field.optional, config)
110 };
111 let conversion = if binding_name != field.name {
113 conversion.replace(&format!("val.{}", field.name), &format!("val.{binding_name}"))
114 } else {
115 conversion
116 };
117 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
119 writeln!(out, " __result.{} = {};", field.name, expr).ok();
120 }
121 }
122 writeln!(out, " __result").ok();
123 writeln!(out, " }}").ok();
124 write!(out, "}}").ok();
125 return out;
126 }
127
128 let optionalized = config.optionalize_defaults && typ.has_default;
129 if optionalized {
130 writeln!(out, " let mut __result = {core_path}::default();").ok();
131 } else {
132 writeln!(out, " Self {{").ok();
133 }
134 for field in &typ.fields {
135 if field.cfg.is_some() {
140 continue;
141 }
142 let references_excluded = !config.exclude_types.is_empty()
149 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types);
150 if references_excluded && typ.has_stripped_cfg_fields {
151 continue;
152 }
153 if optionalized && ((field.sanitized && field.core_wrapper != CoreWrapper::Cow) || references_excluded) {
154 continue;
155 }
156 let field_was_optionalized = optionalized && !field.optional;
157 let conversion = if (field.sanitized && field.core_wrapper != CoreWrapper::Cow) || references_excluded {
158 format!("{}: Default::default()", field.name)
159 } else if field_was_optionalized {
160 field_conversion_to_core_cfg(&field.name, &field.ty, false, config)
163 } else {
164 field_conversion_to_core_cfg(&field.name, &field.ty, field.optional, config)
165 };
166 let conversion = if let Some(newtype_path) = &field.newtype_wrapper {
172 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
173 match &field.ty {
176 TypeRef::Optional(_) => format!("{}: ({expr}).map({newtype_path})", field.name),
177 TypeRef::Vec(_) => {
178 let inner_expr = if let Some(prefix) = expr.strip_suffix(".collect()") {
183 format!("{prefix}.collect::<Vec<_>>()")
184 } else {
185 expr.to_string()
186 };
187 format!(
188 "{}: ({inner_expr}).into_iter().map({newtype_path}).collect()",
189 field.name
190 )
191 }
192 _ if field.optional => format!("{}: ({expr}).map({newtype_path})", field.name),
193 _ => format!("{}: {newtype_path}({expr})", field.name),
194 }
195 } else {
196 conversion
197 }
198 } else {
199 conversion
200 };
201 let conversion = if field.is_boxed && matches!(&field.ty, TypeRef::Named(_)) {
203 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
204 if field.optional {
205 format!("{}: {}.map(Box::new)", field.name, expr)
207 } else {
208 format!("{}: Box::new({})", field.name, expr)
209 }
210 } else {
211 conversion
212 }
213 } else {
214 conversion
215 };
216 let is_opaque_arc_field = field.core_wrapper == CoreWrapper::Arc
224 && matches!(&field.ty, TypeRef::Named(n) if config
225 .opaque_types
226 .is_some_and(|opaque| opaque.contains(n.as_str())));
227 let is_opaque_no_wrapper_field = field.core_wrapper == CoreWrapper::None
231 && matches!(&field.ty, TypeRef::Named(n) if config
232 .opaque_types
233 .is_some_and(|opaque| opaque.contains(n.as_str())));
234 let conversion = if is_opaque_arc_field {
235 if field.optional {
236 format!("{}: val.{}.map(|v| v.inner)", field.name, field.name)
237 } else {
238 format!("{}: val.{}.inner", field.name, field.name)
239 }
240 } else if is_opaque_no_wrapper_field {
241 format!("{}: Default::default()", field.name)
242 } else {
243 apply_core_wrapper_to_core(
244 &conversion,
245 &field.name,
246 &field.core_wrapper,
247 &field.vec_inner_core_wrapper,
248 field.optional,
249 )
250 };
251 let binding_name = config.binding_field_name_owned(&typ.name, &field.name);
255 let conversion = if binding_name != field.name {
256 conversion.replace(&format!("val.{}", field.name), &format!("val.{binding_name}"))
257 } else {
258 conversion
259 };
260 if optionalized {
261 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
262 if field_was_optionalized {
263 writeln!(
264 out,
265 " if let Some(__v) = val.{binding_name} {{ __result.{} = {}; }}",
266 field.name,
267 expr.replace(&format!("val.{binding_name}"), "__v")
268 )
269 .ok();
270 } else {
271 writeln!(out, " __result.{} = {};", field.name, expr).ok();
272 }
273 }
274 } else {
275 writeln!(out, " {conversion},").ok();
276 }
277 }
278 if typ.has_stripped_cfg_fields && !optionalized {
280 writeln!(out, " ..Default::default()").ok();
281 }
282 if optionalized {
283 writeln!(out, " __result").ok();
284 } else {
285 writeln!(out, " }}").ok();
286 }
287 writeln!(out, " }}").ok();
288 write!(out, "}}").ok();
289 out
290}
291
292pub(super) fn gen_optionalized_field_to_core(
297 name: &str,
298 ty: &TypeRef,
299 config: &ConversionConfig,
300 field_is_ir_optional: bool,
301) -> String {
302 match ty {
303 TypeRef::Json => {
304 format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok()).unwrap_or_default()")
305 }
306 TypeRef::Named(_) => {
307 format!("{name}: val.{name}.map(Into::into).unwrap_or_default()")
309 }
310 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
311 format!("{name}: val.{name}.map(|v| v as f32).unwrap_or(0.0)")
312 }
313 TypeRef::Primitive(PrimitiveType::F32 | PrimitiveType::F64) => {
314 format!("{name}: val.{name}.unwrap_or(0.0)")
315 }
316 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
317 let core_ty = core_prim_str(p);
318 format!("{name}: val.{name}.map(|v| v as {core_ty}).unwrap_or_default()")
319 }
320 TypeRef::Optional(inner)
321 if config.cast_large_ints_to_i64
322 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
323 {
324 if let TypeRef::Primitive(p) = inner.as_ref() {
325 let core_ty = core_prim_str(p);
326 format!("{name}: val.{name}.map(|v| v as {core_ty})")
327 } else {
328 field_conversion_to_core(name, ty, false)
329 }
330 }
331 TypeRef::Duration if config.cast_large_ints_to_i64 => {
332 format!("{name}: val.{name}.map(|v| std::time::Duration::from_millis(v as u64)).unwrap_or_default()")
333 }
334 TypeRef::Duration => {
335 format!("{name}: val.{name}.map(std::time::Duration::from_millis).unwrap_or_default()")
336 }
337 TypeRef::Path => {
338 format!("{name}: val.{name}.map(Into::into).unwrap_or_default()")
339 }
340 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
341 format!("{name}: val.{name}.map(|s| std::path::PathBuf::from(s))")
343 }
344 TypeRef::Optional(_) => {
345 format!("{name}: val.{name}.map(Some)")
348 }
349 TypeRef::Char => {
351 format!("{name}: val.{name}.and_then(|s| s.chars().next()).unwrap_or('*')")
352 }
353 TypeRef::Vec(inner) => match inner.as_ref() {
354 TypeRef::Json => {
355 format!(
356 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()).unwrap_or_default()"
357 )
358 }
359 TypeRef::Named(_) => {
360 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect()).unwrap_or_default()")
361 }
362 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
363 let core_ty = core_prim_str(p);
364 format!(
365 "{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect()).unwrap_or_default()"
366 )
367 }
368 _ => format!("{name}: val.{name}.unwrap_or_default()"),
369 },
370 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
371 let k_is_json = matches!(k.as_ref(), TypeRef::Json);
375 let k_expr = if k_is_json {
376 "serde_json::from_str(&k).unwrap_or_default()"
377 } else {
378 "k.into()"
379 };
380 format!(
381 "{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or(serde_json::json!(v)))).collect()"
382 )
383 }
384 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
385 format!(
387 "{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (serde_json::from_str(&k).unwrap_or_default(), v)).collect()"
388 )
389 }
390 TypeRef::Map(k, v) => {
391 let has_named_val = matches!(v.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
393 let has_named_key = matches!(k.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
394 let val_is_string_enum = matches!(v.as_ref(), TypeRef::Named(n)
395 if config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)));
396 if field_is_ir_optional {
397 if val_is_string_enum {
399 format!(
400 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, serde_json::from_str(&v).unwrap_or_default())).collect())"
401 )
402 } else if has_named_val {
403 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
404 } else if has_named_key {
405 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
406 } else {
407 format!("{name}: val.{name}.map(|m| m.into_iter().collect())")
408 }
409 } else if val_is_string_enum {
410 format!(
411 "{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k, serde_json::from_str(&v).unwrap_or_default())).collect()"
412 )
413 } else if has_named_val {
414 format!("{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k, v.into())).collect()")
415 } else if has_named_key {
416 format!("{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k.into(), v)).collect()")
417 } else {
418 format!("{name}: val.{name}.unwrap_or_default().into_iter().collect()")
419 }
420 }
421 _ => {
422 format!("{name}: val.{name}.unwrap_or_default()")
424 }
425 }
426}
427
428pub fn field_conversion_to_core(name: &str, ty: &TypeRef, optional: bool) -> String {
430 match ty {
431 TypeRef::Primitive(_) | TypeRef::String | TypeRef::Unit => {
433 format!("{name}: val.{name}")
434 }
435 TypeRef::Bytes => {
440 if optional {
441 format!("{name}: val.{name}.map(|v| v.to_vec().into())")
442 } else {
443 format!("{name}: val.{name}.to_vec().into()")
444 }
445 }
446 TypeRef::Json => {
448 if optional {
449 format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())")
450 } else {
451 format!("{name}: serde_json::from_str(&val.{name}).unwrap_or_default()")
452 }
453 }
454 TypeRef::Char => {
456 if optional {
457 format!("{name}: val.{name}.and_then(|s| s.chars().next())")
458 } else {
459 format!("{name}: val.{name}.chars().next().unwrap_or('*')")
460 }
461 }
462 TypeRef::Duration => {
464 if optional {
465 format!("{name}: val.{name}.map(std::time::Duration::from_millis)")
466 } else {
467 format!("{name}: std::time::Duration::from_millis(val.{name})")
468 }
469 }
470 TypeRef::Path => {
472 if optional {
473 format!("{name}: val.{name}.map(Into::into)")
474 } else {
475 format!("{name}: val.{name}.into()")
476 }
477 }
478 TypeRef::Named(type_name) if is_tuple_type_name(type_name) => {
481 format!("{name}: val.{name}")
482 }
483 TypeRef::Named(_) => {
484 if optional {
485 format!("{name}: val.{name}.map(Into::into)")
486 } else {
487 format!("{name}: val.{name}.into()")
488 }
489 }
490 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
494 let k_expr = if matches!(k.as_ref(), TypeRef::Json) {
495 "serde_json::from_str(&k).unwrap_or_default()"
496 } else {
497 "k.into()"
498 };
499 if optional {
500 format!(
501 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect())"
502 )
503 } else {
504 format!(
505 "{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect()"
506 )
507 }
508 }
509 TypeRef::Optional(inner) => match inner.as_ref() {
511 TypeRef::Json => format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())"),
512 TypeRef::Named(_) | TypeRef::Path => format!("{name}: val.{name}.map(Into::into)"),
513 TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_)) => {
514 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
515 }
516 _ => format!("{name}: val.{name}"),
517 },
518 TypeRef::Vec(inner) => match inner.as_ref() {
520 TypeRef::Json => {
521 if optional {
522 format!(
523 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect())"
524 )
525 } else {
526 format!("{name}: val.{name}.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()")
527 }
528 }
529 TypeRef::Named(type_name) if is_tuple_type_name(type_name) => {
531 format!("{name}: val.{name}")
532 }
533 TypeRef::Named(_) => {
534 if optional {
535 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
536 } else {
537 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
538 }
539 }
540 _ => format!("{name}: val.{name}"),
541 },
542 TypeRef::Map(k, v) => {
545 let has_named_key = matches!(k.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
546 let has_named_val = matches!(v.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
547 let has_json_val = matches!(v.as_ref(), TypeRef::Json);
548 let has_json_key = matches!(k.as_ref(), TypeRef::Json);
549 let has_vec_named_val = matches!(v.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n)));
551 let has_vec_json_val = matches!(v.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json));
553 if has_json_val || has_json_key || has_named_key || has_named_val || has_vec_named_val || has_vec_json_val {
554 let k_expr = if has_json_key {
558 "serde_json::from_str(&k).unwrap_or(serde_json::Value::String(k))"
559 } else {
560 "k.into()"
561 };
562 let v_expr = if has_json_val {
563 "serde_json::from_str(&v).unwrap_or(serde_json::Value::String(v))"
564 } else if has_named_val {
565 "v.into()"
566 } else if has_vec_named_val {
567 "v.into_iter().map(Into::into).collect()"
568 } else if has_vec_json_val {
569 "v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()"
570 } else {
571 "v"
572 };
573 if optional {
574 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, {v_expr})).collect())")
575 } else {
576 format!("{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, {v_expr})).collect()")
577 }
578 } else {
579 let is_string_map = matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String);
583 if is_string_map {
584 if optional {
585 format!(
586 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())"
587 )
588 } else {
589 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
590 }
591 } else {
592 if optional {
596 if has_named_val {
597 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
598 } else {
599 format!("{name}: val.{name}.map(|m| m.into_iter().collect())")
600 }
601 } else {
602 format!("{name}: val.{name}.into_iter().collect()")
603 }
604 }
605 }
606 }
607 }
608}
609
610pub fn field_conversion_to_core_cfg(name: &str, ty: &TypeRef, optional: bool, config: &ConversionConfig) -> String {
612 if optional && matches!(ty, TypeRef::Optional(_)) {
616 let inner_expr = field_conversion_to_core_cfg(name, ty, false, config);
619 if let Some(expr) = inner_expr.strip_prefix(&format!("{name}: ")) {
621 return format!("{name}: ({expr}).map(Some)");
622 }
623 return inner_expr;
624 }
625
626 if config.map_uses_jsvalue {
628 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
629 let is_vec_json = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json));
630 let is_map = matches!(ty, TypeRef::Map(_, _));
631 if is_nested_vec || is_map || is_vec_json {
632 if optional {
633 return format!(
634 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())"
635 );
636 }
637 return format!("{name}: serde_wasm_bindgen::from_value(val.{name}.clone()).unwrap_or_default()");
638 }
639 if let TypeRef::Optional(inner) = ty {
640 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
641 let is_inner_vec_json = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json));
642 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
643 if is_inner_nested || is_inner_map || is_inner_vec_json {
644 return format!(
645 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())"
646 );
647 }
648 }
649 }
650
651 if config.vec_named_to_string {
655 if let TypeRef::Vec(inner) = ty {
656 if matches!(inner.as_ref(), TypeRef::Named(_)) {
657 if optional {
658 return format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())");
659 }
660 return format!("{name}: serde_json::from_str(&val.{name}).unwrap_or_default()");
661 }
662 }
663 }
664 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
666 return format!("{name}: Default::default()");
667 }
668 if config.map_as_string {
669 if let TypeRef::Optional(inner) = ty {
670 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
671 return format!("{name}: Default::default()");
672 }
673 }
674 }
675 if config.json_to_string && matches!(ty, TypeRef::Json) {
677 return format!("{name}: Default::default()");
678 }
679 if config.map_uses_jsvalue && matches!(ty, TypeRef::Json) {
681 if optional {
682 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())");
683 }
684 return format!("{name}: serde_wasm_bindgen::from_value(val.{name}.clone()).unwrap_or_default()");
685 }
686 if !config.cast_large_ints_to_i64
687 && !config.cast_large_ints_to_f64
688 && !config.cast_uints_to_i32
689 && !config.cast_f32_to_f64
690 && !config.json_to_string
691 && !config.vec_named_to_string
692 && !config.map_as_string
693 && config.from_binding_skip_types.is_empty()
694 {
695 return field_conversion_to_core(name, ty, optional);
696 }
697 match ty {
699 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
700 let core_ty = core_prim_str(p);
701 if optional {
702 format!("{name}: val.{name}.map(|v| v as {core_ty})")
703 } else {
704 format!("{name}: val.{name} as {core_ty}")
705 }
706 }
707 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
709 if optional {
710 format!("{name}: val.{name}.map(|v| v as f32)")
711 } else {
712 format!("{name}: val.{name} as f32")
713 }
714 }
715 TypeRef::Duration if config.cast_large_ints_to_i64 => {
716 if optional {
717 format!("{name}: val.{name}.map(|v| std::time::Duration::from_millis(v as u64))")
718 } else {
719 format!("{name}: std::time::Duration::from_millis(val.{name} as u64)")
720 }
721 }
722 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) => {
723 if let TypeRef::Primitive(p) = inner.as_ref() {
724 let core_ty = core_prim_str(p);
725 format!("{name}: val.{name}.map(|v| v as {core_ty})")
726 } else {
727 field_conversion_to_core(name, ty, optional)
728 }
729 }
730 TypeRef::Vec(inner)
732 if config.cast_large_ints_to_i64
733 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
734 {
735 if let TypeRef::Primitive(p) = inner.as_ref() {
736 let core_ty = core_prim_str(p);
737 if optional {
738 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
739 } else {
740 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
741 }
742 } else {
743 field_conversion_to_core(name, ty, optional)
744 }
745 }
746 TypeRef::Map(_k, v)
748 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
749 {
750 if let TypeRef::Primitive(p) = v.as_ref() {
751 let core_ty = core_prim_str(p);
752 if optional {
753 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
754 } else {
755 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
756 }
757 } else {
758 field_conversion_to_core(name, ty, optional)
759 }
760 }
761 TypeRef::Vec(inner)
763 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
764 {
765 if optional {
766 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
767 } else {
768 format!("{name}: val.{name}.into_iter().map(|v| v as f32).collect()")
769 }
770 }
771 TypeRef::Optional(inner)
773 if config.cast_f32_to_f64
774 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
775 {
776 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
777 }
778 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
780 let core_ty = core_prim_str(p);
781 if optional {
782 format!("{name}: val.{name}.map(|v| v as {core_ty})")
783 } else {
784 format!("{name}: val.{name} as {core_ty}")
785 }
786 }
787 TypeRef::Optional(inner)
789 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
790 {
791 if let TypeRef::Primitive(p) = inner.as_ref() {
792 let core_ty = core_prim_str(p);
793 format!("{name}: val.{name}.map(|v| v as {core_ty})")
794 } else {
795 field_conversion_to_core(name, ty, optional)
796 }
797 }
798 TypeRef::Vec(inner)
800 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
801 {
802 if let TypeRef::Primitive(p) = inner.as_ref() {
803 let core_ty = core_prim_str(p);
804 if optional {
805 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
806 } else {
807 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
808 }
809 } else {
810 field_conversion_to_core(name, ty, optional)
811 }
812 }
813 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
815 let core_ty = core_prim_str(p);
816 if optional {
817 format!("{name}: val.{name}.map(|v| v as {core_ty})")
818 } else {
819 format!("{name}: val.{name} as {core_ty}")
820 }
821 }
822 TypeRef::Optional(inner)
824 if config.cast_large_ints_to_f64
825 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
826 {
827 if let TypeRef::Primitive(p) = inner.as_ref() {
828 let core_ty = core_prim_str(p);
829 format!("{name}: val.{name}.map(|v| v as {core_ty})")
830 } else {
831 field_conversion_to_core(name, ty, optional)
832 }
833 }
834 TypeRef::Vec(inner)
836 if config.cast_large_ints_to_f64
837 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
838 {
839 if let TypeRef::Primitive(p) = inner.as_ref() {
840 let core_ty = core_prim_str(p);
841 if optional {
842 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
843 } else {
844 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
845 }
846 } else {
847 field_conversion_to_core(name, ty, optional)
848 }
849 }
850 TypeRef::Map(_k, v)
852 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
853 {
854 if let TypeRef::Primitive(p) = v.as_ref() {
855 let core_ty = core_prim_str(p);
856 if optional {
857 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
858 } else {
859 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
860 }
861 } else {
862 field_conversion_to_core(name, ty, optional)
863 }
864 }
865 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
868 format!("{name}: Default::default()")
869 }
870 TypeRef::Optional(inner) => match inner.as_ref() {
871 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
872 format!("{name}: Default::default()")
873 }
874 _ => field_conversion_to_core(name, ty, optional),
875 },
876 _ => field_conversion_to_core(name, ty, optional),
878 }
879}
880
881pub fn apply_core_wrapper_to_core(
884 conversion: &str,
885 name: &str,
886 core_wrapper: &CoreWrapper,
887 vec_inner_core_wrapper: &CoreWrapper,
888 optional: bool,
889) -> String {
890 if *vec_inner_core_wrapper == CoreWrapper::Arc {
892 return conversion
893 .replace(
894 ".map(Into::into).collect()",
895 ".map(|v| std::sync::Arc::new(v.into())).collect()",
896 )
897 .replace(
898 "map(|v| v.into_iter().map(Into::into)",
899 "map(|v| v.into_iter().map(|v| std::sync::Arc::new(v.into()))",
900 );
901 }
902
903 match core_wrapper {
904 CoreWrapper::None => conversion.to_string(),
905 CoreWrapper::Cow => {
906 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
910 if optional {
911 format!("{name}: {expr}.map(Into::into)")
912 } else if expr == format!("val.{name}") {
913 format!("{name}: val.{name}.into()")
914 } else if expr == "Default::default()" {
915 conversion.to_string()
918 } else {
919 format!("{name}: ({expr}).into()")
920 }
921 } else {
922 conversion.to_string()
923 }
924 }
925 CoreWrapper::Arc => {
926 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
928 if expr == "Default::default()" {
929 conversion.to_string()
932 } else if optional {
933 format!("{name}: {expr}.map(|v| std::sync::Arc::new(v))")
934 } else {
935 format!("{name}: std::sync::Arc::new({expr})")
936 }
937 } else {
938 conversion.to_string()
939 }
940 }
941 CoreWrapper::Bytes => {
942 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
948 let already_converted_non_opt =
949 expr == format!("val.{name}.into()") || expr == format!("val.{name}.to_vec().into()");
950 let already_converted_opt = expr
951 .strip_prefix(&format!("val.{name}"))
952 .map(|s| s == ".map(Into::into)" || s == ".map(|v| v.to_vec().into())")
953 .unwrap_or(false);
954 if already_converted_non_opt || already_converted_opt {
955 conversion.to_string()
957 } else if optional {
958 format!("{name}: {expr}.map(Into::into)")
959 } else if expr == format!("val.{name}") {
960 format!("{name}: val.{name}.into()")
961 } else if expr == "Default::default()" {
962 conversion.to_string()
965 } else {
966 format!("{name}: ({expr}).into()")
967 }
968 } else {
969 conversion.to_string()
970 }
971 }
972 CoreWrapper::ArcMutex => {
973 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
975 if optional {
976 format!("{name}: {expr}.map(|v| std::sync::Arc::new(std::sync::Mutex::new(v.into())))")
977 } else if expr == format!("val.{name}") {
978 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(val.{name}.into()))")
979 } else {
980 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(({expr}).into()))")
981 }
982 } else {
983 conversion.to_string()
984 }
985 }
986 }
987}
988
989#[cfg(test)]
990mod tests {
991 use super::gen_from_binding_to_core;
992 use alef_core::ir::{CoreWrapper, DefaultValue, FieldDef, TypeDef, TypeRef};
993
994 fn type_with_field(field: FieldDef) -> TypeDef {
995 TypeDef {
996 name: "ProcessConfig".to_string(),
997 rust_path: "crate::ProcessConfig".to_string(),
998 original_rust_path: String::new(),
999 fields: vec![field],
1000 methods: vec![],
1001 is_opaque: false,
1002 is_clone: true,
1003 is_copy: false,
1004 doc: String::new(),
1005 cfg: None,
1006 is_trait: false,
1007 has_default: true,
1008 has_stripped_cfg_fields: false,
1009 is_return_type: false,
1010 serde_rename_all: None,
1011 has_serde: true,
1012 super_traits: vec![],
1013 }
1014 }
1015
1016 #[test]
1017 fn sanitized_cow_string_field_converts_to_core() {
1018 let field = FieldDef {
1019 name: "language".to_string(),
1020 ty: TypeRef::String,
1021 optional: false,
1022 default: None,
1023 doc: String::new(),
1024 sanitized: true,
1025 is_boxed: false,
1026 type_rust_path: None,
1027 cfg: None,
1028 typed_default: Some(DefaultValue::Empty),
1029 core_wrapper: CoreWrapper::Cow,
1030 vec_inner_core_wrapper: CoreWrapper::None,
1031 newtype_wrapper: None,
1032 };
1033
1034 let out = gen_from_binding_to_core(&type_with_field(field), "crate");
1035
1036 assert!(out.contains("language: val.language.into()"));
1037 assert!(!out.contains("language: Default::default()"));
1038 }
1039}