1use alef_core::ir::{CoreWrapper, PrimitiveType, TypeDef, TypeRef};
2
3use super::ConversionConfig;
4use super::helpers::{
5 core_prim_str, core_type_path_remapped, is_newtype, is_tuple_type_name, needs_f64_cast, needs_i32_cast,
6 needs_i64_cast,
7};
8
9pub fn gen_from_binding_to_core(typ: &TypeDef, core_import: &str) -> String {
13 gen_from_binding_to_core_cfg(typ, core_import, &ConversionConfig::default())
14}
15
16pub fn gen_from_binding_to_core_cfg(typ: &TypeDef, core_import: &str, config: &ConversionConfig) -> String {
18 let core_path = core_type_path_remapped(typ, core_import, config.source_crate_remaps);
19 let binding_name = format!("{}{}", config.type_name_prefix, typ.name);
20
21 if is_newtype(typ) {
23 let field = &typ.fields[0];
24 let newtype_inner_expr = match &field.ty {
25 TypeRef::Named(_) => "val._0.into()".to_string(),
26 TypeRef::Path => "val._0.into()".to_string(),
27 TypeRef::Duration => "std::time::Duration::from_millis(val._0)".to_string(),
28 _ => "val._0".to_string(),
29 };
30 return crate::template_env::render(
31 "conversions/binding_to_core_impl",
32 minijinja::context! {
33 core_path => core_path,
34 binding_name => binding_name,
35 is_newtype => true,
36 newtype_inner_expr => newtype_inner_expr,
37 builder_mode => false,
38 uses_builder_pattern => false,
39 has_stripped_cfg_fields => typ.has_stripped_cfg_fields,
40 statements => vec![] as Vec<String>,
41 fields => vec![] as Vec<String>,
42 },
43 );
44 }
45
46 let uses_builder_pattern = (config.option_duration_on_defaults
48 && typ.has_default
49 && typ
50 .fields
51 .iter()
52 .any(|f| !f.optional && matches!(f.ty, TypeRef::Duration)))
53 || (config.optionalize_defaults && typ.has_default);
54
55 let has_optionalized_duration = config.option_duration_on_defaults
60 && typ.has_default
61 && typ
62 .fields
63 .iter()
64 .any(|f| !f.optional && matches!(f.ty, TypeRef::Duration));
65
66 if has_optionalized_duration {
67 let optionalized = config.optionalize_defaults && typ.has_default;
69 let mut statements = Vec::new();
70 for field in &typ.fields {
71 if field.cfg.is_some() {
73 continue;
74 }
75 if field.sanitized && field.core_wrapper != CoreWrapper::Cow {
76 continue;
78 }
79 if !config.exclude_types.is_empty()
81 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types)
82 {
83 continue;
84 }
85 let binding_name_field = config.binding_field_name_owned(&typ.name, &field.name);
87 if !field.optional && matches!(field.ty, TypeRef::Duration) {
88 let cast = if config.cast_large_ints_to_i64 { " as u64" } else { "" };
89 statements.push(format!(
90 "if let Some(__v) = val.{binding_name_field} {{ __result.{} = std::time::Duration::from_millis(__v{cast}); }}",
91 field.name
92 ));
93 continue;
94 }
95 let conversion = if optionalized && !field.optional {
96 gen_optionalized_field_to_core(&field.name, &field.ty, config, false)
97 } else {
98 field_conversion_to_core_cfg(&field.name, &field.ty, field.optional, config)
99 };
100 let conversion = if binding_name_field != field.name {
102 conversion.replace(&format!("val.{}", field.name), &format!("val.{binding_name_field}"))
103 } else {
104 conversion
105 };
106 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
108 statements.push(format!("__result.{} = {};", field.name, expr));
109 }
110 }
111
112 return crate::template_env::render(
113 "conversions/binding_to_core_impl",
114 minijinja::context! {
115 core_path => core_path,
116 binding_name => binding_name,
117 is_newtype => false,
118 newtype_inner_expr => "",
119 builder_mode => true,
120 uses_builder_pattern => uses_builder_pattern,
121 has_stripped_cfg_fields => typ.has_stripped_cfg_fields,
122 statements => statements,
123 fields => vec![] as Vec<String>,
124 },
125 );
126 }
127
128 let optionalized = config.optionalize_defaults && typ.has_default;
129
130 let mut fields = Vec::new();
132 let mut statements = Vec::new();
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_field = config.binding_field_name_owned(&typ.name, &field.name);
255 let conversion = if binding_name_field != field.name {
256 conversion.replace(&format!("val.{}", field.name), &format!("val.{binding_name_field}"))
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 statements.push(format!(
264 "if let Some(__v) = val.{binding_name_field} {{ __result.{} = {}; }}",
265 field.name,
266 expr.replace(&format!("val.{binding_name_field}"), "__v")
267 ));
268 } else {
269 statements.push(format!("__result.{} = {};", field.name, expr));
270 }
271 }
272 } else {
273 fields.push(conversion);
274 }
275 }
276
277 crate::template_env::render(
281 "conversions/binding_to_core_impl",
282 minijinja::context! {
283 core_path => core_path,
284 binding_name => binding_name,
285 is_newtype => false,
286 newtype_inner_expr => "",
287 builder_mode => optionalized,
288 uses_builder_pattern => uses_builder_pattern,
289 has_stripped_cfg_fields => typ.has_stripped_cfg_fields,
290 statements => statements,
291 fields => fields,
292 },
293 )
294}
295
296pub(super) fn gen_optionalized_field_to_core(
301 name: &str,
302 ty: &TypeRef,
303 config: &ConversionConfig,
304 field_is_ir_optional: bool,
305) -> String {
306 match ty {
307 TypeRef::Json => {
308 format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok()).unwrap_or_default()")
309 }
310 TypeRef::Named(_) => {
311 format!("{name}: val.{name}.map(Into::into).unwrap_or_default()")
313 }
314 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
315 format!("{name}: val.{name}.map(|v| v as f32).unwrap_or(0.0)")
316 }
317 TypeRef::Primitive(PrimitiveType::F32 | PrimitiveType::F64) => {
318 format!("{name}: val.{name}.unwrap_or(0.0)")
319 }
320 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
321 let core_ty = core_prim_str(p);
322 format!("{name}: val.{name}.map(|v| v as {core_ty}).unwrap_or_default()")
323 }
324 TypeRef::Optional(inner)
325 if config.cast_large_ints_to_i64
326 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
327 {
328 if let TypeRef::Primitive(p) = inner.as_ref() {
329 let core_ty = core_prim_str(p);
330 format!("{name}: val.{name}.map(|v| v as {core_ty})")
331 } else {
332 field_conversion_to_core(name, ty, false)
333 }
334 }
335 TypeRef::Duration if config.cast_large_ints_to_i64 => {
336 format!("{name}: val.{name}.map(|v| std::time::Duration::from_millis(v as u64)).unwrap_or_default()")
337 }
338 TypeRef::Duration => {
339 format!("{name}: val.{name}.map(std::time::Duration::from_millis).unwrap_or_default()")
340 }
341 TypeRef::Path => {
342 format!("{name}: val.{name}.map(Into::into).unwrap_or_default()")
343 }
344 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
345 format!("{name}: val.{name}.map(|s| std::path::PathBuf::from(s))")
347 }
348 TypeRef::Optional(_) => {
349 format!("{name}: val.{name}.map(Some)")
352 }
353 TypeRef::Char => {
355 format!("{name}: val.{name}.and_then(|s| s.chars().next()).unwrap_or('*')")
356 }
357 TypeRef::Vec(inner) => match inner.as_ref() {
358 TypeRef::Json => {
359 format!(
360 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()).unwrap_or_default()"
361 )
362 }
363 TypeRef::Named(_) => {
364 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect()).unwrap_or_default()")
365 }
366 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
367 let core_ty = core_prim_str(p);
368 format!(
369 "{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect()).unwrap_or_default()"
370 )
371 }
372 _ => format!("{name}: val.{name}.unwrap_or_default()"),
373 },
374 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
375 let k_is_json = matches!(k.as_ref(), TypeRef::Json);
379 let k_expr = if k_is_json {
380 "serde_json::from_str(&k).unwrap_or_default()"
381 } else {
382 "k.into()"
383 };
384 format!(
385 "{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()"
386 )
387 }
388 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
389 format!(
391 "{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (serde_json::from_str(&k).unwrap_or_default(), v)).collect()"
392 )
393 }
394 TypeRef::Map(k, v) => {
395 let has_named_val = matches!(v.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
397 let has_named_key = matches!(k.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
398 let val_is_string_enum = matches!(v.as_ref(), TypeRef::Named(n)
399 if config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)));
400 if field_is_ir_optional {
401 if val_is_string_enum {
403 format!(
404 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, serde_json::from_str(&v).unwrap_or_default())).collect())"
405 )
406 } else if has_named_val {
407 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
408 } else if has_named_key {
409 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
410 } else {
411 format!("{name}: val.{name}.map(|m| m.into_iter().collect())")
412 }
413 } else if val_is_string_enum {
414 format!(
415 "{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k, serde_json::from_str(&v).unwrap_or_default())).collect()"
416 )
417 } else if has_named_val {
418 format!("{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k, v.into())).collect()")
419 } else if has_named_key {
420 format!("{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k.into(), v)).collect()")
421 } else {
422 format!("{name}: val.{name}.unwrap_or_default().into_iter().collect()")
423 }
424 }
425 _ => {
426 format!("{name}: val.{name}.unwrap_or_default()")
428 }
429 }
430}
431
432pub fn field_conversion_to_core(name: &str, ty: &TypeRef, optional: bool) -> String {
434 match ty {
435 TypeRef::Primitive(_) | TypeRef::String | TypeRef::Unit => {
437 format!("{name}: val.{name}")
438 }
439 TypeRef::Bytes => {
444 if optional {
445 format!("{name}: val.{name}.map(|v| v.to_vec().into())")
446 } else {
447 format!("{name}: val.{name}.to_vec().into()")
448 }
449 }
450 TypeRef::Json => {
452 if optional {
453 format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())")
454 } else {
455 format!("{name}: serde_json::from_str(&val.{name}).unwrap_or_default()")
456 }
457 }
458 TypeRef::Char => {
460 if optional {
461 format!("{name}: val.{name}.and_then(|s| s.chars().next())")
462 } else {
463 format!("{name}: val.{name}.chars().next().unwrap_or('*')")
464 }
465 }
466 TypeRef::Duration => {
468 if optional {
469 format!("{name}: val.{name}.map(std::time::Duration::from_millis)")
470 } else {
471 format!("{name}: std::time::Duration::from_millis(val.{name})")
472 }
473 }
474 TypeRef::Path => {
476 if optional {
477 format!("{name}: val.{name}.map(Into::into)")
478 } else {
479 format!("{name}: val.{name}.into()")
480 }
481 }
482 TypeRef::Named(type_name) if is_tuple_type_name(type_name) => {
485 format!("{name}: val.{name}")
486 }
487 TypeRef::Named(_) => {
488 if optional {
489 format!("{name}: val.{name}.map(Into::into)")
490 } else {
491 format!("{name}: val.{name}.into()")
492 }
493 }
494 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
498 let k_expr = if matches!(k.as_ref(), TypeRef::Json) {
499 "serde_json::from_str(&k).unwrap_or_default()"
500 } else {
501 "k.into()"
502 };
503 if optional {
504 format!(
505 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect())"
506 )
507 } else {
508 format!(
509 "{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect()"
510 )
511 }
512 }
513 TypeRef::Optional(inner) => match inner.as_ref() {
515 TypeRef::Json => format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())"),
516 TypeRef::Named(_) | TypeRef::Path => format!("{name}: val.{name}.map(Into::into)"),
517 TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_)) => {
518 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
519 }
520 _ => format!("{name}: val.{name}"),
521 },
522 TypeRef::Vec(inner) => match inner.as_ref() {
524 TypeRef::Json => {
525 if optional {
526 format!(
527 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect())"
528 )
529 } else {
530 format!("{name}: val.{name}.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()")
531 }
532 }
533 TypeRef::Named(type_name) if is_tuple_type_name(type_name) => {
535 format!("{name}: val.{name}")
536 }
537 TypeRef::Named(_) => {
538 if optional {
539 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
540 } else {
541 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
542 }
543 }
544 _ => format!("{name}: val.{name}"),
545 },
546 TypeRef::Map(k, v) => {
549 let has_named_key = matches!(k.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
550 let has_named_val = matches!(v.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
551 let has_json_val = matches!(v.as_ref(), TypeRef::Json);
552 let has_json_key = matches!(k.as_ref(), TypeRef::Json);
553 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)));
555 let has_vec_json_val = matches!(v.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json));
557 if has_json_val || has_json_key || has_named_key || has_named_val || has_vec_named_val || has_vec_json_val {
558 let k_expr = if has_json_key {
562 "serde_json::from_str(&k).unwrap_or(serde_json::Value::String(k))"
563 } else {
564 "k.into()"
565 };
566 let v_expr = if has_json_val {
567 "serde_json::from_str(&v).unwrap_or(serde_json::Value::String(v))"
568 } else if has_named_val {
569 "v.into()"
570 } else if has_vec_named_val {
571 "v.into_iter().map(Into::into).collect()"
572 } else if has_vec_json_val {
573 "v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()"
574 } else {
575 "v"
576 };
577 if optional {
578 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, {v_expr})).collect())")
579 } else {
580 format!("{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, {v_expr})).collect()")
581 }
582 } else {
583 let is_string_map = matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String);
587 if is_string_map {
588 if optional {
589 format!(
590 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())"
591 )
592 } else {
593 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
594 }
595 } else {
596 if optional {
600 if has_named_val {
601 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
602 } else {
603 format!("{name}: val.{name}.map(|m| m.into_iter().collect())")
604 }
605 } else {
606 format!("{name}: val.{name}.into_iter().collect()")
607 }
608 }
609 }
610 }
611 }
612}
613
614pub fn field_conversion_to_core_cfg(name: &str, ty: &TypeRef, optional: bool, config: &ConversionConfig) -> String {
616 if optional && matches!(ty, TypeRef::Optional(_)) {
620 let inner_expr = field_conversion_to_core_cfg(name, ty, false, config);
623 if let Some(expr) = inner_expr.strip_prefix(&format!("{name}: ")) {
625 return format!("{name}: ({expr}).map(Some)");
626 }
627 return inner_expr;
628 }
629
630 if config.map_uses_jsvalue {
632 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
633 let is_vec_json = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json));
634 let is_map = matches!(ty, TypeRef::Map(_, _));
635 if is_nested_vec || is_map || is_vec_json {
636 if optional {
637 return format!(
638 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())"
639 );
640 }
641 return format!("{name}: serde_wasm_bindgen::from_value(val.{name}.clone()).unwrap_or_default()");
642 }
643 if let TypeRef::Optional(inner) = ty {
644 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
645 let is_inner_vec_json = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json));
646 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
647 if is_inner_nested || is_inner_map || is_inner_vec_json {
648 return format!(
649 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())"
650 );
651 }
652 }
653 }
654
655 if config.vec_named_to_string {
659 if let TypeRef::Vec(inner) = ty {
660 if matches!(inner.as_ref(), TypeRef::Named(_)) {
661 if optional {
662 return format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())");
663 }
664 return format!("{name}: serde_json::from_str(&val.{name}).unwrap_or_default()");
665 }
666 }
667 }
668 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
670 return format!("{name}: Default::default()");
671 }
672 if config.map_as_string {
673 if let TypeRef::Optional(inner) = ty {
674 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
675 return format!("{name}: Default::default()");
676 }
677 }
678 }
679 if config.json_to_string && matches!(ty, TypeRef::Json) {
681 return format!("{name}: Default::default()");
682 }
683 if config.map_uses_jsvalue && matches!(ty, TypeRef::Json) {
685 if optional {
686 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())");
687 }
688 return format!("{name}: serde_wasm_bindgen::from_value(val.{name}.clone()).unwrap_or_default()");
689 }
690 if !config.cast_large_ints_to_i64
691 && !config.cast_large_ints_to_f64
692 && !config.cast_uints_to_i32
693 && !config.cast_f32_to_f64
694 && !config.json_to_string
695 && !config.vec_named_to_string
696 && !config.map_as_string
697 && config.from_binding_skip_types.is_empty()
698 {
699 return field_conversion_to_core(name, ty, optional);
700 }
701 match ty {
703 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
704 let core_ty = core_prim_str(p);
705 if optional {
706 format!("{name}: val.{name}.map(|v| v as {core_ty})")
707 } else {
708 format!("{name}: val.{name} as {core_ty}")
709 }
710 }
711 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
713 if optional {
714 format!("{name}: val.{name}.map(|v| v as f32)")
715 } else {
716 format!("{name}: val.{name} as f32")
717 }
718 }
719 TypeRef::Duration if config.cast_large_ints_to_i64 => {
720 if optional {
721 format!("{name}: val.{name}.map(|v| std::time::Duration::from_millis(v as u64))")
722 } else {
723 format!("{name}: std::time::Duration::from_millis(val.{name} as u64)")
724 }
725 }
726 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) => {
727 if let TypeRef::Primitive(p) = inner.as_ref() {
728 let core_ty = core_prim_str(p);
729 format!("{name}: val.{name}.map(|v| v as {core_ty})")
730 } else {
731 field_conversion_to_core(name, ty, optional)
732 }
733 }
734 TypeRef::Vec(inner)
736 if config.cast_large_ints_to_i64
737 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
738 {
739 if let TypeRef::Primitive(p) = inner.as_ref() {
740 let core_ty = core_prim_str(p);
741 if optional {
742 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
743 } else {
744 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
745 }
746 } else {
747 field_conversion_to_core(name, ty, optional)
748 }
749 }
750 TypeRef::Map(_k, v)
752 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
753 {
754 if let TypeRef::Primitive(p) = v.as_ref() {
755 let core_ty = core_prim_str(p);
756 if optional {
757 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
758 } else {
759 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
760 }
761 } else {
762 field_conversion_to_core(name, ty, optional)
763 }
764 }
765 TypeRef::Vec(inner)
767 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
768 {
769 if optional {
770 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
771 } else {
772 format!("{name}: val.{name}.into_iter().map(|v| v as f32).collect()")
773 }
774 }
775 TypeRef::Optional(inner)
777 if config.cast_f32_to_f64
778 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
779 {
780 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
781 }
782 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
784 let core_ty = core_prim_str(p);
785 if optional {
786 format!("{name}: val.{name}.map(|v| v as {core_ty})")
787 } else {
788 format!("{name}: val.{name} as {core_ty}")
789 }
790 }
791 TypeRef::Optional(inner)
793 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
794 {
795 if let TypeRef::Primitive(p) = inner.as_ref() {
796 let core_ty = core_prim_str(p);
797 format!("{name}: val.{name}.map(|v| v as {core_ty})")
798 } else {
799 field_conversion_to_core(name, ty, optional)
800 }
801 }
802 TypeRef::Vec(inner)
804 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
805 {
806 if let TypeRef::Primitive(p) = inner.as_ref() {
807 let core_ty = core_prim_str(p);
808 if optional {
809 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
810 } else {
811 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
812 }
813 } else {
814 field_conversion_to_core(name, ty, optional)
815 }
816 }
817 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
819 let core_ty = core_prim_str(p);
820 if optional {
821 format!("{name}: val.{name}.map(|v| v as {core_ty})")
822 } else {
823 format!("{name}: val.{name} as {core_ty}")
824 }
825 }
826 TypeRef::Optional(inner)
828 if config.cast_large_ints_to_f64
829 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
830 {
831 if let TypeRef::Primitive(p) = inner.as_ref() {
832 let core_ty = core_prim_str(p);
833 format!("{name}: val.{name}.map(|v| v as {core_ty})")
834 } else {
835 field_conversion_to_core(name, ty, optional)
836 }
837 }
838 TypeRef::Vec(inner)
840 if config.cast_large_ints_to_f64
841 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
842 {
843 if let TypeRef::Primitive(p) = inner.as_ref() {
844 let core_ty = core_prim_str(p);
845 if optional {
846 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
847 } else {
848 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
849 }
850 } else {
851 field_conversion_to_core(name, ty, optional)
852 }
853 }
854 TypeRef::Map(_k, v)
856 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
857 {
858 if let TypeRef::Primitive(p) = v.as_ref() {
859 let core_ty = core_prim_str(p);
860 if optional {
861 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
862 } else {
863 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
864 }
865 } else {
866 field_conversion_to_core(name, ty, optional)
867 }
868 }
869 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
872 format!("{name}: Default::default()")
873 }
874 TypeRef::Optional(inner) => match inner.as_ref() {
875 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
876 format!("{name}: Default::default()")
877 }
878 _ => field_conversion_to_core(name, ty, optional),
879 },
880 _ => field_conversion_to_core(name, ty, optional),
882 }
883}
884
885pub fn apply_core_wrapper_to_core(
888 conversion: &str,
889 name: &str,
890 core_wrapper: &CoreWrapper,
891 vec_inner_core_wrapper: &CoreWrapper,
892 optional: bool,
893) -> String {
894 if *vec_inner_core_wrapper == CoreWrapper::Arc {
896 return conversion
897 .replace(
898 ".map(Into::into).collect()",
899 ".map(|v| std::sync::Arc::new(v.into())).collect()",
900 )
901 .replace(
902 "map(|v| v.into_iter().map(Into::into)",
903 "map(|v| v.into_iter().map(|v| std::sync::Arc::new(v.into()))",
904 );
905 }
906
907 match core_wrapper {
908 CoreWrapper::None => conversion.to_string(),
909 CoreWrapper::Cow => {
910 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
914 if optional {
915 format!("{name}: {expr}.map(Into::into)")
916 } else if expr == format!("val.{name}") {
917 format!("{name}: val.{name}.into()")
918 } else if expr == "Default::default()" {
919 conversion.to_string()
922 } else {
923 format!("{name}: ({expr}).into()")
924 }
925 } else {
926 conversion.to_string()
927 }
928 }
929 CoreWrapper::Arc => {
930 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
932 if expr == "Default::default()" {
933 conversion.to_string()
936 } else if optional {
937 format!("{name}: {expr}.map(|v| std::sync::Arc::new(v))")
938 } else {
939 format!("{name}: std::sync::Arc::new({expr})")
940 }
941 } else {
942 conversion.to_string()
943 }
944 }
945 CoreWrapper::Bytes => {
946 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
952 let already_converted_non_opt =
953 expr == format!("val.{name}.into()") || expr == format!("val.{name}.to_vec().into()");
954 let already_converted_opt = expr
955 .strip_prefix(&format!("val.{name}"))
956 .map(|s| s == ".map(Into::into)" || s == ".map(|v| v.to_vec().into())")
957 .unwrap_or(false);
958 if already_converted_non_opt || already_converted_opt {
959 conversion.to_string()
961 } else if optional {
962 format!("{name}: {expr}.map(Into::into)")
963 } else if expr == format!("val.{name}") {
964 format!("{name}: val.{name}.into()")
965 } else if expr == "Default::default()" {
966 conversion.to_string()
969 } else {
970 format!("{name}: ({expr}).into()")
971 }
972 } else {
973 conversion.to_string()
974 }
975 }
976 CoreWrapper::ArcMutex => {
977 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
979 if optional {
980 format!("{name}: {expr}.map(|v| std::sync::Arc::new(std::sync::Mutex::new(v.into())))")
981 } else if expr == format!("val.{name}") {
982 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(val.{name}.into()))")
983 } else {
984 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(({expr}).into()))")
985 }
986 } else {
987 conversion.to_string()
988 }
989 }
990 }
991}
992
993#[cfg(test)]
994mod tests {
995 use super::gen_from_binding_to_core;
996 use alef_core::ir::{CoreWrapper, DefaultValue, FieldDef, TypeDef, TypeRef};
997
998 fn type_with_field(field: FieldDef) -> TypeDef {
999 TypeDef {
1000 name: "ProcessConfig".to_string(),
1001 rust_path: "crate::ProcessConfig".to_string(),
1002 original_rust_path: String::new(),
1003 fields: vec![field],
1004 methods: vec![],
1005 is_opaque: false,
1006 is_clone: true,
1007 is_copy: false,
1008 doc: String::new(),
1009 cfg: None,
1010 is_trait: false,
1011 has_default: true,
1012 has_stripped_cfg_fields: false,
1013 is_return_type: false,
1014 serde_rename_all: None,
1015 has_serde: true,
1016 super_traits: vec![],
1017 }
1018 }
1019
1020 #[test]
1021 fn sanitized_cow_string_field_converts_to_core() {
1022 let field = FieldDef {
1023 name: "language".to_string(),
1024 ty: TypeRef::String,
1025 optional: false,
1026 default: None,
1027 doc: String::new(),
1028 sanitized: true,
1029 is_boxed: false,
1030 type_rust_path: None,
1031 cfg: None,
1032 typed_default: Some(DefaultValue::Empty),
1033 core_wrapper: CoreWrapper::Cow,
1034 vec_inner_core_wrapper: CoreWrapper::None,
1035 newtype_wrapper: None,
1036 };
1037
1038 let out = gen_from_binding_to_core(&type_with_field(field), "crate");
1039
1040 assert!(out.contains("language: val.language.into()"));
1041 assert!(!out.contains("language: Default::default()"));
1042 }
1043}