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.sanitized && field.core_wrapper != CoreWrapper::Cow {
72 continue;
74 }
75 if !config.exclude_types.is_empty()
77 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types)
78 {
79 continue;
80 }
81 let binding_name_field = config.binding_field_name_owned(&typ.name, &field.name);
83 if !field.optional && matches!(field.ty, TypeRef::Duration) {
84 let cast = if config.cast_large_ints_to_i64 { " as u64" } else { "" };
85 statements.push(format!(
86 "if let Some(__v) = val.{binding_name_field} {{ __result.{} = std::time::Duration::from_millis(__v{cast}); }}",
87 field.name
88 ));
89 continue;
90 }
91 let conversion = if optionalized && !field.optional {
92 gen_optionalized_field_to_core(&field.name, &field.ty, config, false)
95 } else {
96 field_conversion_to_core_cfg(&field.name, &field.ty, field.optional, config)
102 };
103 let conversion = if binding_name_field != field.name {
105 conversion.replace(&format!("val.{}", field.name), &format!("val.{binding_name_field}"))
106 } else {
107 conversion
108 };
109 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
111 statements.push(format!("__result.{} = {};", field.name, expr));
112 }
113 }
114
115 return crate::template_env::render(
116 "conversions/binding_to_core_impl",
117 minijinja::context! {
118 core_path => core_path,
119 binding_name => binding_name,
120 is_newtype => false,
121 newtype_inner_expr => "",
122 builder_mode => true,
123 uses_builder_pattern => uses_builder_pattern,
124 has_stripped_cfg_fields => typ.has_stripped_cfg_fields,
125 statements => statements,
126 fields => vec![] as Vec<String>,
127 },
128 );
129 }
130
131 let optionalized = config.optionalize_defaults && typ.has_default;
132
133 let mut fields = Vec::new();
135 let mut statements = Vec::new();
136
137 for field in &typ.fields {
138 let references_excluded = !config.exclude_types.is_empty()
150 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types);
151 if references_excluded && typ.has_stripped_cfg_fields {
152 continue;
153 }
154 if optionalized && ((field.sanitized && field.core_wrapper != CoreWrapper::Cow) || references_excluded) {
155 continue;
156 }
157 let field_was_optionalized = optionalized && !field.optional;
158 let conversion = if (field.sanitized && field.core_wrapper != CoreWrapper::Cow) || references_excluded {
159 format!("{}: Default::default()", field.name)
160 } else if field_was_optionalized {
161 field_conversion_to_core_cfg(&field.name, &field.ty, false, config)
164 } else {
165 field_conversion_to_core_cfg(&field.name, &field.ty, field.optional, config)
166 };
167 let conversion = if let Some(newtype_path) = &field.newtype_wrapper {
173 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
174 match &field.ty {
177 TypeRef::Optional(_) => format!("{}: ({expr}).map({newtype_path})", field.name),
178 TypeRef::Vec(_) => {
179 let inner_expr = if let Some(prefix) = expr.strip_suffix(".collect()") {
184 format!("{prefix}.collect::<Vec<_>>()")
185 } else {
186 expr.to_string()
187 };
188 format!(
189 "{}: ({inner_expr}).into_iter().map({newtype_path}).collect()",
190 field.name
191 )
192 }
193 _ if field.optional => format!("{}: ({expr}).map({newtype_path})", field.name),
194 _ => format!("{}: {newtype_path}({expr})", field.name),
195 }
196 } else {
197 conversion
198 }
199 } else {
200 conversion
201 };
202 let conversion = if field.is_boxed && matches!(&field.ty, TypeRef::Named(_)) {
204 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
205 if field.optional {
206 format!("{}: {}.map(Box::new)", field.name, expr)
208 } else {
209 format!("{}: Box::new({})", field.name, expr)
210 }
211 } else {
212 conversion
213 }
214 } else {
215 conversion
216 };
217 let is_opaque_arc_field = field.core_wrapper == CoreWrapper::Arc
225 && matches!(&field.ty, TypeRef::Named(n) if config
226 .opaque_types
227 .is_some_and(|opaque| opaque.contains(n.as_str())));
228 let is_opaque_no_wrapper_field = field.core_wrapper == CoreWrapper::None
232 && matches!(&field.ty, TypeRef::Named(n) if config
233 .opaque_types
234 .is_some_and(|opaque| opaque.contains(n.as_str())));
235 let conversion = if is_opaque_arc_field {
236 if field.optional {
237 format!("{}: val.{}.map(|v| v.inner)", field.name, field.name)
238 } else {
239 format!("{}: val.{}.inner", field.name, field.name)
240 }
241 } else if is_opaque_no_wrapper_field {
242 format!("{}: Default::default()", field.name)
243 } else {
244 apply_core_wrapper_to_core(
245 &conversion,
246 &field.name,
247 &field.core_wrapper,
248 &field.vec_inner_core_wrapper,
249 field.optional,
250 )
251 };
252 let binding_name_field = config.binding_field_name_owned(&typ.name, &field.name);
256 let conversion = if binding_name_field != field.name {
257 conversion.replace(&format!("val.{}", field.name), &format!("val.{binding_name_field}"))
258 } else {
259 conversion
260 };
261 if optionalized {
262 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
263 if field_was_optionalized {
264 statements.push(format!(
265 "if let Some(__v) = val.{binding_name_field} {{ __result.{} = {}; }}",
266 field.name,
267 expr.replace(&format!("val.{binding_name_field}"), "__v")
268 ));
269 } else {
270 statements.push(format!("__result.{} = {};", field.name, expr));
271 }
272 }
273 } else {
274 fields.push(conversion);
275 }
276 }
277
278 crate::template_env::render(
282 "conversions/binding_to_core_impl",
283 minijinja::context! {
284 core_path => core_path,
285 binding_name => binding_name,
286 is_newtype => false,
287 newtype_inner_expr => "",
288 builder_mode => optionalized,
289 uses_builder_pattern => uses_builder_pattern,
290 has_stripped_cfg_fields => typ.has_stripped_cfg_fields,
291 statements => statements,
292 fields => fields,
293 },
294 )
295}
296
297pub(super) fn gen_optionalized_field_to_core(
302 name: &str,
303 ty: &TypeRef,
304 config: &ConversionConfig,
305 field_is_ir_optional: bool,
306) -> String {
307 match ty {
308 TypeRef::Json if config.json_as_value => {
309 format!("{name}: val.{name}.unwrap_or_default()")
310 }
311 TypeRef::Json => {
312 format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok()).unwrap_or_default()")
313 }
314 TypeRef::Named(_) => {
315 format!("{name}: val.{name}.map(Into::into).unwrap_or_default()")
317 }
318 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
319 format!("{name}: val.{name}.map(|v| v as f32).unwrap_or(0.0)")
320 }
321 TypeRef::Primitive(PrimitiveType::F32 | PrimitiveType::F64) => {
322 format!("{name}: val.{name}.unwrap_or(0.0)")
323 }
324 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
325 let core_ty = core_prim_str(p);
326 format!("{name}: val.{name}.map(|v| v as {core_ty}).unwrap_or_default()")
327 }
328 TypeRef::Optional(inner)
329 if config.cast_large_ints_to_i64
330 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
331 {
332 if let TypeRef::Primitive(p) = inner.as_ref() {
333 let core_ty = core_prim_str(p);
334 format!("{name}: val.{name}.map(|v| v as {core_ty})")
335 } else {
336 field_conversion_to_core(name, ty, false)
337 }
338 }
339 TypeRef::Duration if config.cast_large_ints_to_i64 => {
340 format!("{name}: val.{name}.map(|v| std::time::Duration::from_millis(v as u64)).unwrap_or_default()")
341 }
342 TypeRef::Duration => {
343 format!("{name}: val.{name}.map(std::time::Duration::from_millis).unwrap_or_default()")
344 }
345 TypeRef::Path => {
346 format!("{name}: val.{name}.map(Into::into).unwrap_or_default()")
347 }
348 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
349 format!("{name}: val.{name}.map(|s| std::path::PathBuf::from(s))")
351 }
352 TypeRef::Optional(_) => {
353 format!("{name}: val.{name}.map(Some)")
356 }
357 TypeRef::Char => {
359 format!("{name}: val.{name}.and_then(|s| s.chars().next()).unwrap_or('*')")
360 }
361 TypeRef::Vec(inner) => match inner.as_ref() {
362 TypeRef::Json => {
363 format!(
364 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()).unwrap_or_default()"
365 )
366 }
367 TypeRef::Named(_) => {
368 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect()).unwrap_or_default()")
369 }
370 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
371 let core_ty = core_prim_str(p);
372 format!(
373 "{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect()).unwrap_or_default()"
374 )
375 }
376 _ => format!("{name}: val.{name}.unwrap_or_default()"),
377 },
378 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
379 let k_is_json = matches!(k.as_ref(), TypeRef::Json);
383 let k_expr = if k_is_json {
384 "serde_json::from_str(&k).unwrap_or_default()"
385 } else {
386 "k.into()"
387 };
388 format!(
389 "{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()"
390 )
391 }
392 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
393 format!(
395 "{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (serde_json::from_str(&k).unwrap_or_default(), v)).collect()"
396 )
397 }
398 TypeRef::Map(k, v) => {
399 let has_named_val = matches!(v.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
401 let has_named_key = matches!(k.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
402 let val_is_string_enum = matches!(v.as_ref(), TypeRef::Named(n)
403 if config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)));
404 if field_is_ir_optional {
405 if val_is_string_enum {
407 format!(
408 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, serde_json::from_str(&v).unwrap_or_default())).collect())"
409 )
410 } else if has_named_val {
411 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
412 } else if has_named_key {
413 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
414 } else {
415 format!("{name}: val.{name}.map(|m| m.into_iter().collect())")
416 }
417 } else if val_is_string_enum {
418 format!(
419 "{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k, serde_json::from_str(&v).unwrap_or_default())).collect()"
420 )
421 } else if has_named_val {
422 format!("{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k, v.into())).collect()")
423 } else if has_named_key {
424 format!("{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k.into(), v)).collect()")
425 } else {
426 format!("{name}: val.{name}.unwrap_or_default().into_iter().collect()")
427 }
428 }
429 _ => {
430 format!("{name}: val.{name}.unwrap_or_default()")
432 }
433 }
434}
435
436pub fn field_conversion_to_core(name: &str, ty: &TypeRef, optional: bool) -> String {
438 match ty {
439 TypeRef::Primitive(_) | TypeRef::String | TypeRef::Unit => {
441 format!("{name}: val.{name}")
442 }
443 TypeRef::Bytes => {
448 if optional {
449 format!("{name}: val.{name}.map(|v| v.to_vec().into())")
450 } else {
451 format!("{name}: val.{name}.to_vec().into()")
452 }
453 }
454 TypeRef::Json => {
456 if optional {
457 format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())")
458 } else {
459 format!("{name}: serde_json::from_str(&val.{name}).unwrap_or_default()")
460 }
461 }
462 TypeRef::Char => {
464 if optional {
465 format!("{name}: val.{name}.and_then(|s| s.chars().next())")
466 } else {
467 format!("{name}: val.{name}.chars().next().unwrap_or('*')")
468 }
469 }
470 TypeRef::Duration => {
472 if optional {
473 format!("{name}: val.{name}.map(std::time::Duration::from_millis)")
474 } else {
475 format!("{name}: std::time::Duration::from_millis(val.{name})")
476 }
477 }
478 TypeRef::Path => {
480 if optional {
481 format!("{name}: val.{name}.map(Into::into)")
482 } else {
483 format!("{name}: val.{name}.into()")
484 }
485 }
486 TypeRef::Named(type_name) if is_tuple_type_name(type_name) => {
489 format!("{name}: val.{name}")
490 }
491 TypeRef::Named(_) => {
492 if optional {
493 format!("{name}: val.{name}.map(Into::into)")
494 } else {
495 format!("{name}: val.{name}.into()")
496 }
497 }
498 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
502 let k_expr = if matches!(k.as_ref(), TypeRef::Json) {
503 "serde_json::from_str(&k).unwrap_or_default()"
504 } else {
505 "k.into()"
506 };
507 if optional {
508 format!(
509 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect())"
510 )
511 } else {
512 format!(
513 "{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect()"
514 )
515 }
516 }
517 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Bytes) => {
520 if optional {
521 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect())")
522 } else {
523 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect()")
524 }
525 }
526 TypeRef::Optional(inner) => match inner.as_ref() {
528 TypeRef::Json => format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())"),
529 TypeRef::Named(_) | TypeRef::Path => format!("{name}: val.{name}.map(Into::into)"),
530 TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_)) => {
531 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
532 }
533 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
534 let k_expr = if matches!(k.as_ref(), TypeRef::Json) {
535 "serde_json::from_str(&k).unwrap_or_default()"
536 } else {
537 "k.into()"
538 };
539 format!(
540 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect())"
541 )
542 }
543 _ => format!("{name}: val.{name}"),
544 },
545 TypeRef::Vec(inner) => match inner.as_ref() {
547 TypeRef::Json => {
548 if optional {
549 format!(
550 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect())"
551 )
552 } else {
553 format!("{name}: val.{name}.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()")
554 }
555 }
556 TypeRef::Named(type_name) if is_tuple_type_name(type_name) => {
558 format!("{name}: val.{name}")
559 }
560 TypeRef::Named(_) => {
561 if optional {
562 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
563 } else {
564 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
565 }
566 }
567 _ => format!("{name}: val.{name}"),
568 },
569 TypeRef::Map(k, v) => {
572 let has_named_key = matches!(k.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
573 let has_named_val = matches!(v.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
574 let has_json_val = matches!(v.as_ref(), TypeRef::Json);
575 let has_json_key = matches!(k.as_ref(), TypeRef::Json);
576 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)));
578 let has_vec_json_val = matches!(v.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json));
580 if has_json_val || has_json_key || has_named_key || has_named_val || has_vec_named_val || has_vec_json_val {
581 let k_expr = if has_json_key {
585 "serde_json::from_str(&k).unwrap_or(serde_json::Value::String(k))"
586 } else {
587 "k.into()"
588 };
589 let v_expr = if has_json_val {
590 "serde_json::from_str(&v).unwrap_or(serde_json::Value::String(v))"
591 } else if has_named_val {
592 "v.into()"
593 } else if has_vec_named_val {
594 "v.into_iter().map(Into::into).collect()"
595 } else if has_vec_json_val {
596 "v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()"
597 } else {
598 "v"
599 };
600 if optional {
601 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, {v_expr})).collect())")
602 } else {
603 format!("{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, {v_expr})).collect()")
604 }
605 } else {
606 let is_string_map = matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String);
610 if is_string_map {
611 if optional {
612 format!(
613 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())"
614 )
615 } else {
616 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
617 }
618 } else {
619 if optional {
623 if has_named_val {
624 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
625 } else {
626 format!("{name}: val.{name}.map(|m| m.into_iter().collect())")
627 }
628 } else {
629 format!("{name}: val.{name}.into_iter().collect()")
630 }
631 }
632 }
633 }
634 }
635}
636
637pub fn field_conversion_to_core_cfg(name: &str, ty: &TypeRef, optional: bool, config: &ConversionConfig) -> String {
639 if optional && matches!(ty, TypeRef::Optional(_)) {
643 let inner_expr = field_conversion_to_core_cfg(name, ty, false, config);
646 if let Some(expr) = inner_expr.strip_prefix(&format!("{name}: ")) {
648 return format!("{name}: ({expr}).map(Some)");
649 }
650 return inner_expr;
651 }
652
653 if config.map_uses_jsvalue {
655 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
656 let is_vec_json = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json));
657 let is_map = matches!(ty, TypeRef::Map(_, _));
658 if is_nested_vec || is_map || is_vec_json {
659 if optional {
660 return format!(
661 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())"
662 );
663 }
664 return format!("{name}: serde_wasm_bindgen::from_value(val.{name}.clone()).unwrap_or_default()");
665 }
666 if let TypeRef::Optional(inner) = ty {
667 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
668 let is_inner_vec_json = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json));
669 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
670 if is_inner_nested || is_inner_map || is_inner_vec_json {
671 return format!(
672 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())"
673 );
674 }
675 }
676 }
677
678 if config.vec_named_to_string {
682 if let TypeRef::Vec(inner) = ty {
683 if matches!(inner.as_ref(), TypeRef::Named(_)) {
684 if optional {
685 return format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())");
686 }
687 return format!("{name}: serde_json::from_str(&val.{name}).unwrap_or_default()");
688 }
689 }
690 }
691 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
693 return format!("{name}: Default::default()");
694 }
695 if config.map_as_string {
696 if let TypeRef::Optional(inner) = ty {
697 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
698 return format!("{name}: Default::default()");
699 }
700 }
701 }
702 if let Some(untagged_names) = config.untagged_data_enum_names {
705 let direct_named = matches!(ty, TypeRef::Named(n) if untagged_names.contains(n));
706 let optional_named = matches!(ty, TypeRef::Optional(inner)
707 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
708 let vec_named = matches!(ty, TypeRef::Vec(inner)
709 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
710 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
711 if matches!(outer.as_ref(), TypeRef::Vec(inner)
712 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n))));
713 if direct_named {
714 if optional {
715 return format!("{name}: val.{name}.and_then(|v| serde_json::from_value(v).ok())");
716 }
717 return format!("{name}: serde_json::from_value(val.{name}).unwrap_or_default()");
718 }
719 if optional_named {
720 return format!("{name}: val.{name}.and_then(|v| serde_json::from_value(v).ok())");
721 }
722 if vec_named {
723 if optional {
724 return format!(
725 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|x| serde_json::from_value(x).ok()).collect())"
726 );
727 }
728 return format!("{name}: val.{name}.into_iter().filter_map(|x| serde_json::from_value(x).ok()).collect()");
729 }
730 if optional_vec_named {
731 return format!(
732 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|x| serde_json::from_value(x).ok()).collect())"
733 );
734 }
735 }
736 if config.json_to_string && matches!(ty, TypeRef::Json) {
738 return format!("{name}: Default::default()");
739 }
740 if config.json_as_value && matches!(ty, TypeRef::Json) {
742 return format!("{name}: val.{name}");
743 }
744 if config.json_as_value {
745 if let TypeRef::Optional(inner) = ty {
746 if matches!(inner.as_ref(), TypeRef::Json) {
747 return format!("{name}: val.{name}");
748 }
749 }
750 if let TypeRef::Vec(inner) = ty {
751 if matches!(inner.as_ref(), TypeRef::Json) {
752 if optional {
753 return format!("{name}: val.{name}.unwrap_or_default()");
754 }
755 return format!("{name}: val.{name}");
756 }
757 }
758 if let TypeRef::Map(_k, v) = ty {
759 if matches!(v.as_ref(), TypeRef::Json) {
760 if optional {
761 return format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())");
762 }
763 return format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v)).collect()");
764 }
765 }
766 }
767 if config.map_uses_jsvalue && matches!(ty, TypeRef::Json) {
769 if optional {
770 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())");
771 }
772 return format!("{name}: serde_wasm_bindgen::from_value(val.{name}.clone()).unwrap_or_default()");
773 }
774 if !config.cast_large_ints_to_i64
775 && !config.cast_large_ints_to_f64
776 && !config.cast_uints_to_i32
777 && !config.cast_f32_to_f64
778 && !config.json_to_string
779 && !config.vec_named_to_string
780 && !config.map_as_string
781 && config.from_binding_skip_types.is_empty()
782 {
783 return field_conversion_to_core(name, ty, optional);
784 }
785 match ty {
787 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
788 let core_ty = core_prim_str(p);
789 if optional {
790 format!("{name}: val.{name}.map(|v| v as {core_ty})")
791 } else {
792 format!("{name}: val.{name} as {core_ty}")
793 }
794 }
795 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
797 if optional {
798 format!("{name}: val.{name}.map(|v| v as f32)")
799 } else {
800 format!("{name}: val.{name} as f32")
801 }
802 }
803 TypeRef::Duration if config.cast_large_ints_to_i64 => {
804 if optional {
805 format!("{name}: val.{name}.map(|v| std::time::Duration::from_millis(v as u64))")
806 } else {
807 format!("{name}: std::time::Duration::from_millis(val.{name} as u64)")
808 }
809 }
810 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) => {
811 if let TypeRef::Primitive(p) = inner.as_ref() {
812 let core_ty = core_prim_str(p);
813 format!("{name}: val.{name}.map(|v| v as {core_ty})")
814 } else {
815 field_conversion_to_core(name, ty, optional)
816 }
817 }
818 TypeRef::Vec(inner)
820 if config.cast_large_ints_to_i64
821 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
822 {
823 if let TypeRef::Primitive(p) = inner.as_ref() {
824 let core_ty = core_prim_str(p);
825 if optional {
826 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
827 } else {
828 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
829 }
830 } else {
831 field_conversion_to_core(name, ty, optional)
832 }
833 }
834 TypeRef::Map(_k, v)
836 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
837 {
838 if let TypeRef::Primitive(p) = v.as_ref() {
839 let core_ty = core_prim_str(p);
840 if optional {
841 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
842 } else {
843 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
844 }
845 } else {
846 field_conversion_to_core(name, ty, optional)
847 }
848 }
849 TypeRef::Vec(inner)
851 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
852 {
853 if optional {
854 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
855 } else {
856 format!("{name}: val.{name}.into_iter().map(|v| v as f32).collect()")
857 }
858 }
859 TypeRef::Optional(inner)
861 if config.cast_f32_to_f64
862 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
863 {
864 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
865 }
866 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
868 let core_ty = core_prim_str(p);
869 if optional {
870 format!("{name}: val.{name}.map(|v| v as {core_ty})")
871 } else {
872 format!("{name}: val.{name} as {core_ty}")
873 }
874 }
875 TypeRef::Optional(inner)
877 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
878 {
879 if let TypeRef::Primitive(p) = inner.as_ref() {
880 let core_ty = core_prim_str(p);
881 format!("{name}: val.{name}.map(|v| v as {core_ty})")
882 } else {
883 field_conversion_to_core(name, ty, optional)
884 }
885 }
886 TypeRef::Vec(inner)
888 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
889 {
890 if let TypeRef::Primitive(p) = inner.as_ref() {
891 let core_ty = core_prim_str(p);
892 if optional {
893 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
894 } else {
895 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
896 }
897 } else {
898 field_conversion_to_core(name, ty, optional)
899 }
900 }
901 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
903 let core_ty = core_prim_str(p);
904 if optional {
905 format!("{name}: val.{name}.map(|v| v as {core_ty})")
906 } else {
907 format!("{name}: val.{name} as {core_ty}")
908 }
909 }
910 TypeRef::Optional(inner)
912 if config.cast_large_ints_to_f64
913 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
914 {
915 if let TypeRef::Primitive(p) = inner.as_ref() {
916 let core_ty = core_prim_str(p);
917 format!("{name}: val.{name}.map(|v| v as {core_ty})")
918 } else {
919 field_conversion_to_core(name, ty, optional)
920 }
921 }
922 TypeRef::Vec(inner)
924 if config.cast_large_ints_to_f64
925 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
926 {
927 if let TypeRef::Primitive(p) = inner.as_ref() {
928 let core_ty = core_prim_str(p);
929 if optional {
930 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
931 } else {
932 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
933 }
934 } else {
935 field_conversion_to_core(name, ty, optional)
936 }
937 }
938 TypeRef::Map(_k, v)
940 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
941 {
942 if let TypeRef::Primitive(p) = v.as_ref() {
943 let core_ty = core_prim_str(p);
944 if optional {
945 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
946 } else {
947 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
948 }
949 } else {
950 field_conversion_to_core(name, ty, optional)
951 }
952 }
953 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
956 format!("{name}: Default::default()")
957 }
958 TypeRef::Optional(inner) => match inner.as_ref() {
959 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
960 format!("{name}: Default::default()")
961 }
962 _ => field_conversion_to_core(name, ty, optional),
963 },
964 _ => field_conversion_to_core(name, ty, optional),
966 }
967}
968
969pub fn apply_core_wrapper_to_core(
972 conversion: &str,
973 name: &str,
974 core_wrapper: &CoreWrapper,
975 vec_inner_core_wrapper: &CoreWrapper,
976 optional: bool,
977) -> String {
978 if *vec_inner_core_wrapper == CoreWrapper::Arc {
980 return conversion
981 .replace(
982 ".map(Into::into).collect()",
983 ".map(|v| std::sync::Arc::new(v.into())).collect()",
984 )
985 .replace(
986 "map(|v| v.into_iter().map(Into::into)",
987 "map(|v| v.into_iter().map(|v| std::sync::Arc::new(v.into()))",
988 );
989 }
990
991 match core_wrapper {
992 CoreWrapper::None => conversion.to_string(),
993 CoreWrapper::Cow => {
994 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
998 if optional {
999 format!("{name}: {expr}.map(Into::into)")
1000 } else if expr == format!("val.{name}") {
1001 format!("{name}: val.{name}.into()")
1002 } else if expr == "Default::default()" {
1003 conversion.to_string()
1006 } else {
1007 format!("{name}: ({expr}).into()")
1008 }
1009 } else {
1010 conversion.to_string()
1011 }
1012 }
1013 CoreWrapper::Arc => {
1014 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1016 if expr == "Default::default()" {
1017 conversion.to_string()
1020 } else if optional {
1021 format!("{name}: {expr}.map(|v| std::sync::Arc::new(v))")
1022 } else {
1023 format!("{name}: std::sync::Arc::new({expr})")
1024 }
1025 } else {
1026 conversion.to_string()
1027 }
1028 }
1029 CoreWrapper::Bytes => {
1030 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1036 let already_converted_non_opt =
1037 expr == format!("val.{name}.into()") || expr == format!("val.{name}.to_vec().into()");
1038 let already_converted_opt = expr
1039 .strip_prefix(&format!("val.{name}"))
1040 .map(|s| s == ".map(Into::into)" || s == ".map(|v| v.to_vec().into())")
1041 .unwrap_or(false);
1042 if already_converted_non_opt || already_converted_opt {
1043 conversion.to_string()
1045 } else if optional {
1046 format!("{name}: {expr}.map(Into::into)")
1047 } else if expr == format!("val.{name}") {
1048 format!("{name}: val.{name}.into()")
1049 } else if expr == "Default::default()" {
1050 conversion.to_string()
1053 } else {
1054 format!("{name}: ({expr}).into()")
1055 }
1056 } else {
1057 conversion.to_string()
1058 }
1059 }
1060 CoreWrapper::ArcMutex => {
1061 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1063 if optional {
1064 format!("{name}: {expr}.map(|v| std::sync::Arc::new(std::sync::Mutex::new(v.into())))")
1065 } else if expr == format!("val.{name}") {
1066 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(val.{name}.into()))")
1067 } else {
1068 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(({expr}).into()))")
1069 }
1070 } else {
1071 conversion.to_string()
1072 }
1073 }
1074 }
1075}
1076
1077#[cfg(test)]
1078mod tests {
1079 use super::gen_from_binding_to_core;
1080 use alef_core::ir::{CoreWrapper, DefaultValue, FieldDef, TypeDef, TypeRef};
1081
1082 fn type_with_field(field: FieldDef) -> TypeDef {
1083 TypeDef {
1084 name: "ProcessConfig".to_string(),
1085 rust_path: "crate::ProcessConfig".to_string(),
1086 original_rust_path: String::new(),
1087 fields: vec![field],
1088 methods: vec![],
1089 is_opaque: false,
1090 is_clone: true,
1091 is_copy: false,
1092 doc: String::new(),
1093 cfg: None,
1094 is_trait: false,
1095 has_default: true,
1096 has_stripped_cfg_fields: false,
1097 is_return_type: false,
1098 serde_rename_all: None,
1099 has_serde: true,
1100 super_traits: vec![],
1101 }
1102 }
1103
1104 #[test]
1105 fn sanitized_cow_string_field_converts_to_core() {
1106 let field = FieldDef {
1107 name: "language".to_string(),
1108 ty: TypeRef::String,
1109 optional: false,
1110 default: None,
1111 doc: String::new(),
1112 sanitized: true,
1113 is_boxed: false,
1114 type_rust_path: None,
1115 cfg: None,
1116 typed_default: Some(DefaultValue::Empty),
1117 core_wrapper: CoreWrapper::Cow,
1118 vec_inner_core_wrapper: CoreWrapper::None,
1119 newtype_wrapper: None,
1120 serde_rename: None,
1121 serde_flatten: false,
1122 };
1123
1124 let out = gen_from_binding_to_core(&type_with_field(field), "crate");
1125
1126 assert!(out.contains("language: val.language.into()"));
1127 assert!(!out.contains("language: Default::default()"));
1128 }
1129}