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)
99 } else {
100 field_conversion_to_core_cfg(&field.name, &field.ty, field.optional, config)
106 };
107 let conversion = if binding_name_field != field.name {
109 conversion.replace(&format!("val.{}", field.name), &format!("val.{binding_name_field}"))
110 } else {
111 conversion
112 };
113 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
115 statements.push(format!("__result.{} = {};", field.name, expr));
116 }
117 }
118
119 return crate::template_env::render(
120 "conversions/binding_to_core_impl",
121 minijinja::context! {
122 core_path => core_path,
123 binding_name => binding_name,
124 is_newtype => false,
125 newtype_inner_expr => "",
126 builder_mode => true,
127 uses_builder_pattern => uses_builder_pattern,
128 has_stripped_cfg_fields => typ.has_stripped_cfg_fields,
129 statements => statements,
130 fields => vec![] as Vec<String>,
131 },
132 );
133 }
134
135 let optionalized = config.optionalize_defaults && typ.has_default;
136
137 let mut fields = Vec::new();
139 let mut statements = Vec::new();
140
141 for field in &typ.fields {
142 if field.cfg.is_some() {
147 continue;
148 }
149 let references_excluded = !config.exclude_types.is_empty()
156 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types);
157 if references_excluded && typ.has_stripped_cfg_fields {
158 continue;
159 }
160 if optionalized && ((field.sanitized && field.core_wrapper != CoreWrapper::Cow) || references_excluded) {
161 continue;
162 }
163 let field_was_optionalized = optionalized && !field.optional;
164 let conversion = if (field.sanitized && field.core_wrapper != CoreWrapper::Cow) || references_excluded {
165 format!("{}: Default::default()", field.name)
166 } else if field_was_optionalized {
167 field_conversion_to_core_cfg(&field.name, &field.ty, false, config)
170 } else {
171 field_conversion_to_core_cfg(&field.name, &field.ty, field.optional, config)
172 };
173 let conversion = if let Some(newtype_path) = &field.newtype_wrapper {
179 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
180 match &field.ty {
183 TypeRef::Optional(_) => format!("{}: ({expr}).map({newtype_path})", field.name),
184 TypeRef::Vec(_) => {
185 let inner_expr = if let Some(prefix) = expr.strip_suffix(".collect()") {
190 format!("{prefix}.collect::<Vec<_>>()")
191 } else {
192 expr.to_string()
193 };
194 format!(
195 "{}: ({inner_expr}).into_iter().map({newtype_path}).collect()",
196 field.name
197 )
198 }
199 _ if field.optional => format!("{}: ({expr}).map({newtype_path})", field.name),
200 _ => format!("{}: {newtype_path}({expr})", field.name),
201 }
202 } else {
203 conversion
204 }
205 } else {
206 conversion
207 };
208 let conversion = if field.is_boxed && matches!(&field.ty, TypeRef::Named(_)) {
210 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
211 if field.optional {
212 format!("{}: {}.map(Box::new)", field.name, expr)
214 } else {
215 format!("{}: Box::new({})", field.name, expr)
216 }
217 } else {
218 conversion
219 }
220 } else {
221 conversion
222 };
223 let is_opaque_arc_field = field.core_wrapper == CoreWrapper::Arc
231 && matches!(&field.ty, TypeRef::Named(n) if config
232 .opaque_types
233 .is_some_and(|opaque| opaque.contains(n.as_str())));
234 let is_opaque_no_wrapper_field = field.core_wrapper == CoreWrapper::None
238 && matches!(&field.ty, TypeRef::Named(n) if config
239 .opaque_types
240 .is_some_and(|opaque| opaque.contains(n.as_str())));
241 let conversion = if is_opaque_arc_field {
242 if field.optional {
243 format!("{}: val.{}.map(|v| v.inner)", field.name, field.name)
244 } else {
245 format!("{}: val.{}.inner", field.name, field.name)
246 }
247 } else if is_opaque_no_wrapper_field {
248 format!("{}: Default::default()", field.name)
249 } else {
250 apply_core_wrapper_to_core(
251 &conversion,
252 &field.name,
253 &field.core_wrapper,
254 &field.vec_inner_core_wrapper,
255 field.optional,
256 )
257 };
258 let binding_name_field = config.binding_field_name_owned(&typ.name, &field.name);
262 let conversion = if binding_name_field != field.name {
263 conversion.replace(&format!("val.{}", field.name), &format!("val.{binding_name_field}"))
264 } else {
265 conversion
266 };
267 if optionalized {
268 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
269 if field_was_optionalized {
270 statements.push(format!(
271 "if let Some(__v) = val.{binding_name_field} {{ __result.{} = {}; }}",
272 field.name,
273 expr.replace(&format!("val.{binding_name_field}"), "__v")
274 ));
275 } else {
276 statements.push(format!("__result.{} = {};", field.name, expr));
277 }
278 }
279 } else {
280 fields.push(conversion);
281 }
282 }
283
284 crate::template_env::render(
288 "conversions/binding_to_core_impl",
289 minijinja::context! {
290 core_path => core_path,
291 binding_name => binding_name,
292 is_newtype => false,
293 newtype_inner_expr => "",
294 builder_mode => optionalized,
295 uses_builder_pattern => uses_builder_pattern,
296 has_stripped_cfg_fields => typ.has_stripped_cfg_fields,
297 statements => statements,
298 fields => fields,
299 },
300 )
301}
302
303pub(super) fn gen_optionalized_field_to_core(
308 name: &str,
309 ty: &TypeRef,
310 config: &ConversionConfig,
311 field_is_ir_optional: bool,
312) -> String {
313 match ty {
314 TypeRef::Json if config.json_as_value => {
315 format!("{name}: val.{name}.unwrap_or_default()")
316 }
317 TypeRef::Json => {
318 format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok()).unwrap_or_default()")
319 }
320 TypeRef::Named(_) => {
321 format!("{name}: val.{name}.map(Into::into).unwrap_or_default()")
323 }
324 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
325 format!("{name}: val.{name}.map(|v| v as f32).unwrap_or(0.0)")
326 }
327 TypeRef::Primitive(PrimitiveType::F32 | PrimitiveType::F64) => {
328 format!("{name}: val.{name}.unwrap_or(0.0)")
329 }
330 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
331 let core_ty = core_prim_str(p);
332 format!("{name}: val.{name}.map(|v| v as {core_ty}).unwrap_or_default()")
333 }
334 TypeRef::Optional(inner)
335 if config.cast_large_ints_to_i64
336 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
337 {
338 if let TypeRef::Primitive(p) = inner.as_ref() {
339 let core_ty = core_prim_str(p);
340 format!("{name}: val.{name}.map(|v| v as {core_ty})")
341 } else {
342 field_conversion_to_core(name, ty, false)
343 }
344 }
345 TypeRef::Duration if config.cast_large_ints_to_i64 => {
346 format!("{name}: val.{name}.map(|v| std::time::Duration::from_millis(v as u64)).unwrap_or_default()")
347 }
348 TypeRef::Duration => {
349 format!("{name}: val.{name}.map(std::time::Duration::from_millis).unwrap_or_default()")
350 }
351 TypeRef::Path => {
352 format!("{name}: val.{name}.map(Into::into).unwrap_or_default()")
353 }
354 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
355 format!("{name}: val.{name}.map(|s| std::path::PathBuf::from(s))")
357 }
358 TypeRef::Optional(_) => {
359 format!("{name}: val.{name}.map(Some)")
362 }
363 TypeRef::Char => {
365 format!("{name}: val.{name}.and_then(|s| s.chars().next()).unwrap_or('*')")
366 }
367 TypeRef::Vec(inner) => match inner.as_ref() {
368 TypeRef::Json => {
369 format!(
370 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()).unwrap_or_default()"
371 )
372 }
373 TypeRef::Named(_) => {
374 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect()).unwrap_or_default()")
375 }
376 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
377 let core_ty = core_prim_str(p);
378 format!(
379 "{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect()).unwrap_or_default()"
380 )
381 }
382 _ => format!("{name}: val.{name}.unwrap_or_default()"),
383 },
384 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
385 let k_is_json = matches!(k.as_ref(), TypeRef::Json);
389 let k_expr = if k_is_json {
390 "serde_json::from_str(&k).unwrap_or_default()"
391 } else {
392 "k.into()"
393 };
394 format!(
395 "{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()"
396 )
397 }
398 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
399 format!(
401 "{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (serde_json::from_str(&k).unwrap_or_default(), v)).collect()"
402 )
403 }
404 TypeRef::Map(k, v) => {
405 let has_named_val = matches!(v.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
407 let has_named_key = matches!(k.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
408 let val_is_string_enum = matches!(v.as_ref(), TypeRef::Named(n)
409 if config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)));
410 if field_is_ir_optional {
411 if val_is_string_enum {
413 format!(
414 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, serde_json::from_str(&v).unwrap_or_default())).collect())"
415 )
416 } else if has_named_val {
417 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
418 } else if has_named_key {
419 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
420 } else {
421 format!("{name}: val.{name}.map(|m| m.into_iter().collect())")
422 }
423 } else if val_is_string_enum {
424 format!(
425 "{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k, serde_json::from_str(&v).unwrap_or_default())).collect()"
426 )
427 } else if has_named_val {
428 format!("{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k, v.into())).collect()")
429 } else if has_named_key {
430 format!("{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k.into(), v)).collect()")
431 } else {
432 format!("{name}: val.{name}.unwrap_or_default().into_iter().collect()")
433 }
434 }
435 _ => {
436 format!("{name}: val.{name}.unwrap_or_default()")
438 }
439 }
440}
441
442pub fn field_conversion_to_core(name: &str, ty: &TypeRef, optional: bool) -> String {
444 match ty {
445 TypeRef::Primitive(_) | TypeRef::String | TypeRef::Unit => {
447 format!("{name}: val.{name}")
448 }
449 TypeRef::Bytes => {
454 if optional {
455 format!("{name}: val.{name}.map(|v| v.to_vec().into())")
456 } else {
457 format!("{name}: val.{name}.to_vec().into()")
458 }
459 }
460 TypeRef::Json => {
462 if optional {
463 format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())")
464 } else {
465 format!("{name}: serde_json::from_str(&val.{name}).unwrap_or_default()")
466 }
467 }
468 TypeRef::Char => {
470 if optional {
471 format!("{name}: val.{name}.and_then(|s| s.chars().next())")
472 } else {
473 format!("{name}: val.{name}.chars().next().unwrap_or('*')")
474 }
475 }
476 TypeRef::Duration => {
478 if optional {
479 format!("{name}: val.{name}.map(std::time::Duration::from_millis)")
480 } else {
481 format!("{name}: std::time::Duration::from_millis(val.{name})")
482 }
483 }
484 TypeRef::Path => {
486 if optional {
487 format!("{name}: val.{name}.map(Into::into)")
488 } else {
489 format!("{name}: val.{name}.into()")
490 }
491 }
492 TypeRef::Named(type_name) if is_tuple_type_name(type_name) => {
495 format!("{name}: val.{name}")
496 }
497 TypeRef::Named(_) => {
498 if optional {
499 format!("{name}: val.{name}.map(Into::into)")
500 } else {
501 format!("{name}: val.{name}.into()")
502 }
503 }
504 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
508 let k_expr = if matches!(k.as_ref(), TypeRef::Json) {
509 "serde_json::from_str(&k).unwrap_or_default()"
510 } else {
511 "k.into()"
512 };
513 if optional {
514 format!(
515 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect())"
516 )
517 } else {
518 format!(
519 "{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect()"
520 )
521 }
522 }
523 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Bytes) => {
526 if optional {
527 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect())")
528 } else {
529 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect()")
530 }
531 }
532 TypeRef::Optional(inner) => match inner.as_ref() {
534 TypeRef::Json => format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())"),
535 TypeRef::Named(_) | TypeRef::Path => format!("{name}: val.{name}.map(Into::into)"),
536 TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_)) => {
537 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
538 }
539 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
540 let k_expr = if matches!(k.as_ref(), TypeRef::Json) {
541 "serde_json::from_str(&k).unwrap_or_default()"
542 } else {
543 "k.into()"
544 };
545 format!(
546 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect())"
547 )
548 }
549 _ => format!("{name}: val.{name}"),
550 },
551 TypeRef::Vec(inner) => match inner.as_ref() {
553 TypeRef::Json => {
554 if optional {
555 format!(
556 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect())"
557 )
558 } else {
559 format!("{name}: val.{name}.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()")
560 }
561 }
562 TypeRef::Named(type_name) if is_tuple_type_name(type_name) => {
564 format!("{name}: val.{name}")
565 }
566 TypeRef::Named(_) => {
567 if optional {
568 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
569 } else {
570 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
571 }
572 }
573 _ => format!("{name}: val.{name}"),
574 },
575 TypeRef::Map(k, v) => {
578 let has_named_key = matches!(k.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
579 let has_named_val = matches!(v.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
580 let has_json_val = matches!(v.as_ref(), TypeRef::Json);
581 let has_json_key = matches!(k.as_ref(), TypeRef::Json);
582 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)));
584 let has_vec_json_val = matches!(v.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json));
586 if has_json_val || has_json_key || has_named_key || has_named_val || has_vec_named_val || has_vec_json_val {
587 let k_expr = if has_json_key {
591 "serde_json::from_str(&k).unwrap_or(serde_json::Value::String(k))"
592 } else {
593 "k.into()"
594 };
595 let v_expr = if has_json_val {
596 "serde_json::from_str(&v).unwrap_or(serde_json::Value::String(v))"
597 } else if has_named_val {
598 "v.into()"
599 } else if has_vec_named_val {
600 "v.into_iter().map(Into::into).collect()"
601 } else if has_vec_json_val {
602 "v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()"
603 } else {
604 "v"
605 };
606 if optional {
607 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, {v_expr})).collect())")
608 } else {
609 format!("{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, {v_expr})).collect()")
610 }
611 } else {
612 let is_string_map = matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String);
616 if is_string_map {
617 if optional {
618 format!(
619 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())"
620 )
621 } else {
622 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
623 }
624 } else {
625 if optional {
629 if has_named_val {
630 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
631 } else {
632 format!("{name}: val.{name}.map(|m| m.into_iter().collect())")
633 }
634 } else {
635 format!("{name}: val.{name}.into_iter().collect()")
636 }
637 }
638 }
639 }
640 }
641}
642
643pub fn field_conversion_to_core_cfg(name: &str, ty: &TypeRef, optional: bool, config: &ConversionConfig) -> String {
645 if optional && matches!(ty, TypeRef::Optional(_)) {
649 let inner_expr = field_conversion_to_core_cfg(name, ty, false, config);
652 if let Some(expr) = inner_expr.strip_prefix(&format!("{name}: ")) {
654 return format!("{name}: ({expr}).map(Some)");
655 }
656 return inner_expr;
657 }
658
659 if config.map_uses_jsvalue {
661 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
662 let is_vec_json = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json));
663 let is_map = matches!(ty, TypeRef::Map(_, _));
664 if is_nested_vec || is_map || is_vec_json {
665 if optional {
666 return format!(
667 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())"
668 );
669 }
670 return format!("{name}: serde_wasm_bindgen::from_value(val.{name}.clone()).unwrap_or_default()");
671 }
672 if let TypeRef::Optional(inner) = ty {
673 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
674 let is_inner_vec_json = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json));
675 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
676 if is_inner_nested || is_inner_map || is_inner_vec_json {
677 return format!(
678 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())"
679 );
680 }
681 }
682 }
683
684 if config.vec_named_to_string {
688 if let TypeRef::Vec(inner) = ty {
689 if matches!(inner.as_ref(), TypeRef::Named(_)) {
690 if optional {
691 return format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())");
692 }
693 return format!("{name}: serde_json::from_str(&val.{name}).unwrap_or_default()");
694 }
695 }
696 }
697 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
699 return format!("{name}: Default::default()");
700 }
701 if config.map_as_string {
702 if let TypeRef::Optional(inner) = ty {
703 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
704 return format!("{name}: Default::default()");
705 }
706 }
707 }
708 if let Some(untagged_names) = config.untagged_data_enum_names {
711 let direct_named = matches!(ty, TypeRef::Named(n) if untagged_names.contains(n));
712 let optional_named = matches!(ty, TypeRef::Optional(inner)
713 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
714 let vec_named = matches!(ty, TypeRef::Vec(inner)
715 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
716 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
717 if matches!(outer.as_ref(), TypeRef::Vec(inner)
718 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n))));
719 if direct_named {
720 if optional {
721 return format!("{name}: val.{name}.and_then(|v| serde_json::from_value(v).ok())");
722 }
723 return format!("{name}: serde_json::from_value(val.{name}).unwrap_or_default()");
724 }
725 if optional_named {
726 return format!("{name}: val.{name}.and_then(|v| serde_json::from_value(v).ok())");
727 }
728 if vec_named {
729 if optional {
730 return format!(
731 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|x| serde_json::from_value(x).ok()).collect())"
732 );
733 }
734 return format!("{name}: val.{name}.into_iter().filter_map(|x| serde_json::from_value(x).ok()).collect()");
735 }
736 if optional_vec_named {
737 return format!(
738 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|x| serde_json::from_value(x).ok()).collect())"
739 );
740 }
741 }
742 if config.json_to_string && matches!(ty, TypeRef::Json) {
744 return format!("{name}: Default::default()");
745 }
746 if config.json_as_value && matches!(ty, TypeRef::Json) {
748 return format!("{name}: val.{name}");
749 }
750 if config.json_as_value {
751 if let TypeRef::Optional(inner) = ty {
752 if matches!(inner.as_ref(), TypeRef::Json) {
753 return format!("{name}: val.{name}");
754 }
755 }
756 if let TypeRef::Vec(inner) = ty {
757 if matches!(inner.as_ref(), TypeRef::Json) {
758 if optional {
759 return format!("{name}: val.{name}.unwrap_or_default()");
760 }
761 return format!("{name}: val.{name}");
762 }
763 }
764 if let TypeRef::Map(_k, v) = ty {
765 if matches!(v.as_ref(), TypeRef::Json) {
766 if optional {
767 return format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())");
768 }
769 return format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v)).collect()");
770 }
771 }
772 }
773 if config.map_uses_jsvalue && matches!(ty, TypeRef::Json) {
775 if optional {
776 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())");
777 }
778 return format!("{name}: serde_wasm_bindgen::from_value(val.{name}.clone()).unwrap_or_default()");
779 }
780 if !config.cast_large_ints_to_i64
781 && !config.cast_large_ints_to_f64
782 && !config.cast_uints_to_i32
783 && !config.cast_f32_to_f64
784 && !config.json_to_string
785 && !config.vec_named_to_string
786 && !config.map_as_string
787 && config.from_binding_skip_types.is_empty()
788 {
789 return field_conversion_to_core(name, ty, optional);
790 }
791 match ty {
793 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
794 let core_ty = core_prim_str(p);
795 if optional {
796 format!("{name}: val.{name}.map(|v| v as {core_ty})")
797 } else {
798 format!("{name}: val.{name} as {core_ty}")
799 }
800 }
801 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
803 if optional {
804 format!("{name}: val.{name}.map(|v| v as f32)")
805 } else {
806 format!("{name}: val.{name} as f32")
807 }
808 }
809 TypeRef::Duration if config.cast_large_ints_to_i64 => {
810 if optional {
811 format!("{name}: val.{name}.map(|v| std::time::Duration::from_millis(v as u64))")
812 } else {
813 format!("{name}: std::time::Duration::from_millis(val.{name} as u64)")
814 }
815 }
816 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) => {
817 if let TypeRef::Primitive(p) = inner.as_ref() {
818 let core_ty = core_prim_str(p);
819 format!("{name}: val.{name}.map(|v| v as {core_ty})")
820 } else {
821 field_conversion_to_core(name, ty, optional)
822 }
823 }
824 TypeRef::Vec(inner)
826 if config.cast_large_ints_to_i64
827 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
828 {
829 if let TypeRef::Primitive(p) = inner.as_ref() {
830 let core_ty = core_prim_str(p);
831 if optional {
832 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
833 } else {
834 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
835 }
836 } else {
837 field_conversion_to_core(name, ty, optional)
838 }
839 }
840 TypeRef::Map(_k, v)
842 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
843 {
844 if let TypeRef::Primitive(p) = v.as_ref() {
845 let core_ty = core_prim_str(p);
846 if optional {
847 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
848 } else {
849 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
850 }
851 } else {
852 field_conversion_to_core(name, ty, optional)
853 }
854 }
855 TypeRef::Vec(inner)
857 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
858 {
859 if optional {
860 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
861 } else {
862 format!("{name}: val.{name}.into_iter().map(|v| v as f32).collect()")
863 }
864 }
865 TypeRef::Optional(inner)
867 if config.cast_f32_to_f64
868 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
869 {
870 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
871 }
872 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
874 let core_ty = core_prim_str(p);
875 if optional {
876 format!("{name}: val.{name}.map(|v| v as {core_ty})")
877 } else {
878 format!("{name}: val.{name} as {core_ty}")
879 }
880 }
881 TypeRef::Optional(inner)
883 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
884 {
885 if let TypeRef::Primitive(p) = inner.as_ref() {
886 let core_ty = core_prim_str(p);
887 format!("{name}: val.{name}.map(|v| v as {core_ty})")
888 } else {
889 field_conversion_to_core(name, ty, optional)
890 }
891 }
892 TypeRef::Vec(inner)
894 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
895 {
896 if let TypeRef::Primitive(p) = inner.as_ref() {
897 let core_ty = core_prim_str(p);
898 if optional {
899 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
900 } else {
901 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
902 }
903 } else {
904 field_conversion_to_core(name, ty, optional)
905 }
906 }
907 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
909 let core_ty = core_prim_str(p);
910 if optional {
911 format!("{name}: val.{name}.map(|v| v as {core_ty})")
912 } else {
913 format!("{name}: val.{name} as {core_ty}")
914 }
915 }
916 TypeRef::Optional(inner)
918 if config.cast_large_ints_to_f64
919 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
920 {
921 if let TypeRef::Primitive(p) = inner.as_ref() {
922 let core_ty = core_prim_str(p);
923 format!("{name}: val.{name}.map(|v| v as {core_ty})")
924 } else {
925 field_conversion_to_core(name, ty, optional)
926 }
927 }
928 TypeRef::Vec(inner)
930 if config.cast_large_ints_to_f64
931 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
932 {
933 if let TypeRef::Primitive(p) = inner.as_ref() {
934 let core_ty = core_prim_str(p);
935 if optional {
936 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
937 } else {
938 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
939 }
940 } else {
941 field_conversion_to_core(name, ty, optional)
942 }
943 }
944 TypeRef::Map(_k, v)
946 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
947 {
948 if let TypeRef::Primitive(p) = v.as_ref() {
949 let core_ty = core_prim_str(p);
950 if optional {
951 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
952 } else {
953 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
954 }
955 } else {
956 field_conversion_to_core(name, ty, optional)
957 }
958 }
959 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
962 format!("{name}: Default::default()")
963 }
964 TypeRef::Optional(inner) => match inner.as_ref() {
965 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
966 format!("{name}: Default::default()")
967 }
968 _ => field_conversion_to_core(name, ty, optional),
969 },
970 _ => field_conversion_to_core(name, ty, optional),
972 }
973}
974
975pub fn apply_core_wrapper_to_core(
978 conversion: &str,
979 name: &str,
980 core_wrapper: &CoreWrapper,
981 vec_inner_core_wrapper: &CoreWrapper,
982 optional: bool,
983) -> String {
984 if *vec_inner_core_wrapper == CoreWrapper::Arc {
986 return conversion
987 .replace(
988 ".map(Into::into).collect()",
989 ".map(|v| std::sync::Arc::new(v.into())).collect()",
990 )
991 .replace(
992 "map(|v| v.into_iter().map(Into::into)",
993 "map(|v| v.into_iter().map(|v| std::sync::Arc::new(v.into()))",
994 );
995 }
996
997 match core_wrapper {
998 CoreWrapper::None => conversion.to_string(),
999 CoreWrapper::Cow => {
1000 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1004 if optional {
1005 format!("{name}: {expr}.map(Into::into)")
1006 } else if expr == format!("val.{name}") {
1007 format!("{name}: val.{name}.into()")
1008 } else if expr == "Default::default()" {
1009 conversion.to_string()
1012 } else {
1013 format!("{name}: ({expr}).into()")
1014 }
1015 } else {
1016 conversion.to_string()
1017 }
1018 }
1019 CoreWrapper::Arc => {
1020 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1022 if expr == "Default::default()" {
1023 conversion.to_string()
1026 } else if optional {
1027 format!("{name}: {expr}.map(|v| std::sync::Arc::new(v))")
1028 } else {
1029 format!("{name}: std::sync::Arc::new({expr})")
1030 }
1031 } else {
1032 conversion.to_string()
1033 }
1034 }
1035 CoreWrapper::Bytes => {
1036 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1042 let already_converted_non_opt =
1043 expr == format!("val.{name}.into()") || expr == format!("val.{name}.to_vec().into()");
1044 let already_converted_opt = expr
1045 .strip_prefix(&format!("val.{name}"))
1046 .map(|s| s == ".map(Into::into)" || s == ".map(|v| v.to_vec().into())")
1047 .unwrap_or(false);
1048 if already_converted_non_opt || already_converted_opt {
1049 conversion.to_string()
1051 } else if optional {
1052 format!("{name}: {expr}.map(Into::into)")
1053 } else if expr == format!("val.{name}") {
1054 format!("{name}: val.{name}.into()")
1055 } else if expr == "Default::default()" {
1056 conversion.to_string()
1059 } else {
1060 format!("{name}: ({expr}).into()")
1061 }
1062 } else {
1063 conversion.to_string()
1064 }
1065 }
1066 CoreWrapper::ArcMutex => {
1067 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1069 if optional {
1070 format!("{name}: {expr}.map(|v| std::sync::Arc::new(std::sync::Mutex::new(v.into())))")
1071 } else if expr == format!("val.{name}") {
1072 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(val.{name}.into()))")
1073 } else {
1074 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(({expr}).into()))")
1075 }
1076 } else {
1077 conversion.to_string()
1078 }
1079 }
1080 }
1081}
1082
1083#[cfg(test)]
1084mod tests {
1085 use super::gen_from_binding_to_core;
1086 use alef_core::ir::{CoreWrapper, DefaultValue, FieldDef, TypeDef, TypeRef};
1087
1088 fn type_with_field(field: FieldDef) -> TypeDef {
1089 TypeDef {
1090 name: "ProcessConfig".to_string(),
1091 rust_path: "crate::ProcessConfig".to_string(),
1092 original_rust_path: String::new(),
1093 fields: vec![field],
1094 methods: vec![],
1095 is_opaque: false,
1096 is_clone: true,
1097 is_copy: false,
1098 doc: String::new(),
1099 cfg: None,
1100 is_trait: false,
1101 has_default: true,
1102 has_stripped_cfg_fields: false,
1103 is_return_type: false,
1104 serde_rename_all: None,
1105 has_serde: true,
1106 super_traits: vec![],
1107 }
1108 }
1109
1110 #[test]
1111 fn sanitized_cow_string_field_converts_to_core() {
1112 let field = FieldDef {
1113 name: "language".to_string(),
1114 ty: TypeRef::String,
1115 optional: false,
1116 default: None,
1117 doc: String::new(),
1118 sanitized: true,
1119 is_boxed: false,
1120 type_rust_path: None,
1121 cfg: None,
1122 typed_default: Some(DefaultValue::Empty),
1123 core_wrapper: CoreWrapper::Cow,
1124 vec_inner_core_wrapper: CoreWrapper::None,
1125 newtype_wrapper: None,
1126 serde_rename: None,
1127 serde_flatten: false,
1128 };
1129
1130 let out = gen_from_binding_to_core(&type_with_field(field), "crate");
1131
1132 assert!(out.contains("language: val.language.into()"));
1133 assert!(!out.contains("language: Default::default()"));
1134 }
1135}