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