1use alef_core::ir::{CoreWrapper, PrimitiveType, TypeDef, TypeRef};
2
3use super::ConversionConfig;
4use super::helpers::{
5 core_prim_str, core_type_path_remapped, is_newtype, is_tuple_type_name, needs_f64_cast, needs_i32_cast,
6 needs_i64_cast,
7};
8
9pub fn gen_from_binding_to_core(typ: &TypeDef, core_import: &str) -> String {
13 gen_from_binding_to_core_cfg(typ, core_import, &ConversionConfig::default())
14}
15
16pub fn gen_from_binding_to_core_cfg(typ: &TypeDef, core_import: &str, config: &ConversionConfig) -> String {
18 let core_path = core_type_path_remapped(typ, core_import, config.source_crate_remaps);
19 let binding_name = format!("{}{}", config.type_name_prefix, typ.name);
20
21 if is_newtype(typ) {
23 let field = &typ.fields[0];
24 let newtype_inner_expr = match &field.ty {
25 TypeRef::Named(_) => "val._0.into()".to_string(),
26 TypeRef::Path => "val._0.into()".to_string(),
27 TypeRef::Duration => "std::time::Duration::from_millis(val._0)".to_string(),
28 _ => "val._0".to_string(),
29 };
30 return crate::template_env::render(
31 "conversions/binding_to_core_impl",
32 minijinja::context! {
33 core_path => core_path,
34 binding_name => binding_name,
35 is_newtype => true,
36 newtype_inner_expr => newtype_inner_expr,
37 builder_mode => false,
38 uses_builder_pattern => false,
39 has_stripped_cfg_fields => typ.has_stripped_cfg_fields,
40 statements => vec![] as Vec<String>,
41 fields => vec![] as Vec<String>,
42 },
43 );
44 }
45
46 let uses_builder_pattern = (config.option_duration_on_defaults
48 && typ.has_default
49 && typ
50 .fields
51 .iter()
52 .any(|f| !f.optional && matches!(f.ty, TypeRef::Duration)))
53 || (config.optionalize_defaults && typ.has_default);
54
55 let has_optionalized_duration = config.option_duration_on_defaults
60 && typ.has_default
61 && typ
62 .fields
63 .iter()
64 .any(|f| !f.optional && matches!(f.ty, TypeRef::Duration));
65
66 if has_optionalized_duration {
67 let optionalized = config.optionalize_defaults && typ.has_default;
69 let mut statements = Vec::new();
70 for field in &typ.fields {
71 if field.cfg.is_some() {
73 continue;
74 }
75 if field.sanitized && field.core_wrapper != CoreWrapper::Cow {
76 continue;
78 }
79 if !config.exclude_types.is_empty()
81 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types)
82 {
83 continue;
84 }
85 let binding_name_field = config.binding_field_name_owned(&typ.name, &field.name);
87 if !field.optional && matches!(field.ty, TypeRef::Duration) {
88 let cast = if config.cast_large_ints_to_i64 { " as u64" } else { "" };
89 statements.push(format!(
90 "if let Some(__v) = val.{binding_name_field} {{ __result.{} = std::time::Duration::from_millis(__v{cast}); }}",
91 field.name
92 ));
93 continue;
94 }
95 let conversion = if optionalized && !field.optional {
96 gen_optionalized_field_to_core(&field.name, &field.ty, config, false)
97 } else if field.optional {
98 gen_optionalized_field_to_core(&field.name, &field.ty, config, true)
99 } else {
100 field_conversion_to_core_cfg(&field.name, &field.ty, field.optional, config)
101 };
102 let conversion = if binding_name_field != field.name {
104 conversion.replace(&format!("val.{}", field.name), &format!("val.{binding_name_field}"))
105 } else {
106 conversion
107 };
108 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
110 statements.push(format!("__result.{} = {};", field.name, expr));
111 }
112 }
113
114 return crate::template_env::render(
115 "conversions/binding_to_core_impl",
116 minijinja::context! {
117 core_path => core_path,
118 binding_name => binding_name,
119 is_newtype => false,
120 newtype_inner_expr => "",
121 builder_mode => true,
122 uses_builder_pattern => uses_builder_pattern,
123 has_stripped_cfg_fields => typ.has_stripped_cfg_fields,
124 statements => statements,
125 fields => vec![] as Vec<String>,
126 },
127 );
128 }
129
130 let optionalized = config.optionalize_defaults && typ.has_default;
131
132 let mut fields = Vec::new();
134 let mut statements = Vec::new();
135
136 for field in &typ.fields {
137 if field.cfg.is_some() {
142 continue;
143 }
144 let references_excluded = !config.exclude_types.is_empty()
151 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types);
152 if references_excluded && typ.has_stripped_cfg_fields {
153 continue;
154 }
155 if optionalized && ((field.sanitized && field.core_wrapper != CoreWrapper::Cow) || references_excluded) {
156 continue;
157 }
158 let field_was_optionalized = optionalized && !field.optional;
159 let conversion = if (field.sanitized && field.core_wrapper != CoreWrapper::Cow) || references_excluded {
160 format!("{}: Default::default()", field.name)
161 } else if field_was_optionalized {
162 field_conversion_to_core_cfg(&field.name, &field.ty, false, config)
165 } else {
166 field_conversion_to_core_cfg(&field.name, &field.ty, field.optional, config)
167 };
168 let conversion = if let Some(newtype_path) = &field.newtype_wrapper {
174 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
175 match &field.ty {
178 TypeRef::Optional(_) => format!("{}: ({expr}).map({newtype_path})", field.name),
179 TypeRef::Vec(_) => {
180 let inner_expr = if let Some(prefix) = expr.strip_suffix(".collect()") {
185 format!("{prefix}.collect::<Vec<_>>()")
186 } else {
187 expr.to_string()
188 };
189 format!(
190 "{}: ({inner_expr}).into_iter().map({newtype_path}).collect()",
191 field.name
192 )
193 }
194 _ if field.optional => format!("{}: ({expr}).map({newtype_path})", field.name),
195 _ => format!("{}: {newtype_path}({expr})", field.name),
196 }
197 } else {
198 conversion
199 }
200 } else {
201 conversion
202 };
203 let conversion = if field.is_boxed && matches!(&field.ty, TypeRef::Named(_)) {
205 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
206 if field.optional {
207 format!("{}: {}.map(Box::new)", field.name, expr)
209 } else {
210 format!("{}: Box::new({})", field.name, expr)
211 }
212 } else {
213 conversion
214 }
215 } else {
216 conversion
217 };
218 let is_opaque_arc_field = field.core_wrapper == CoreWrapper::Arc
226 && matches!(&field.ty, TypeRef::Named(n) if config
227 .opaque_types
228 .is_some_and(|opaque| opaque.contains(n.as_str())));
229 let is_opaque_no_wrapper_field = field.core_wrapper == CoreWrapper::None
233 && matches!(&field.ty, TypeRef::Named(n) if config
234 .opaque_types
235 .is_some_and(|opaque| opaque.contains(n.as_str())));
236 let conversion = if is_opaque_arc_field {
237 if field.optional {
238 format!("{}: val.{}.map(|v| v.inner)", field.name, field.name)
239 } else {
240 format!("{}: val.{}.inner", field.name, field.name)
241 }
242 } else if is_opaque_no_wrapper_field {
243 format!("{}: Default::default()", field.name)
244 } else {
245 apply_core_wrapper_to_core(
246 &conversion,
247 &field.name,
248 &field.core_wrapper,
249 &field.vec_inner_core_wrapper,
250 field.optional,
251 )
252 };
253 let binding_name_field = config.binding_field_name_owned(&typ.name, &field.name);
257 let conversion = if binding_name_field != field.name {
258 conversion.replace(&format!("val.{}", field.name), &format!("val.{binding_name_field}"))
259 } else {
260 conversion
261 };
262 if optionalized {
263 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
264 if field_was_optionalized {
265 statements.push(format!(
266 "if let Some(__v) = val.{binding_name_field} {{ __result.{} = {}; }}",
267 field.name,
268 expr.replace(&format!("val.{binding_name_field}"), "__v")
269 ));
270 } else {
271 statements.push(format!("__result.{} = {};", field.name, expr));
272 }
273 }
274 } else {
275 fields.push(conversion);
276 }
277 }
278
279 crate::template_env::render(
283 "conversions/binding_to_core_impl",
284 minijinja::context! {
285 core_path => core_path,
286 binding_name => binding_name,
287 is_newtype => false,
288 newtype_inner_expr => "",
289 builder_mode => optionalized,
290 uses_builder_pattern => uses_builder_pattern,
291 has_stripped_cfg_fields => typ.has_stripped_cfg_fields,
292 statements => statements,
293 fields => fields,
294 },
295 )
296}
297
298pub(super) fn gen_optionalized_field_to_core(
303 name: &str,
304 ty: &TypeRef,
305 config: &ConversionConfig,
306 field_is_ir_optional: bool,
307) -> String {
308 match ty {
309 TypeRef::Json if config.json_as_value => {
310 format!("{name}: val.{name}.unwrap_or_default()")
311 }
312 TypeRef::Json => {
313 format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok()).unwrap_or_default()")
314 }
315 TypeRef::Named(_) => {
316 format!("{name}: val.{name}.map(Into::into).unwrap_or_default()")
318 }
319 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
320 format!("{name}: val.{name}.map(|v| v as f32).unwrap_or(0.0)")
321 }
322 TypeRef::Primitive(PrimitiveType::F32 | PrimitiveType::F64) => {
323 format!("{name}: val.{name}.unwrap_or(0.0)")
324 }
325 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
326 let core_ty = core_prim_str(p);
327 format!("{name}: val.{name}.map(|v| v as {core_ty}).unwrap_or_default()")
328 }
329 TypeRef::Optional(inner)
330 if config.cast_large_ints_to_i64
331 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
332 {
333 if let TypeRef::Primitive(p) = inner.as_ref() {
334 let core_ty = core_prim_str(p);
335 format!("{name}: val.{name}.map(|v| v as {core_ty})")
336 } else {
337 field_conversion_to_core(name, ty, false)
338 }
339 }
340 TypeRef::Duration if config.cast_large_ints_to_i64 => {
341 format!("{name}: val.{name}.map(|v| std::time::Duration::from_millis(v as u64)).unwrap_or_default()")
342 }
343 TypeRef::Duration => {
344 format!("{name}: val.{name}.map(std::time::Duration::from_millis).unwrap_or_default()")
345 }
346 TypeRef::Path => {
347 format!("{name}: val.{name}.map(Into::into).unwrap_or_default()")
348 }
349 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
350 format!("{name}: val.{name}.map(|s| std::path::PathBuf::from(s))")
352 }
353 TypeRef::Optional(_) => {
354 format!("{name}: val.{name}.map(Some)")
357 }
358 TypeRef::Char => {
360 format!("{name}: val.{name}.and_then(|s| s.chars().next()).unwrap_or('*')")
361 }
362 TypeRef::Vec(inner) => match inner.as_ref() {
363 TypeRef::Json => {
364 format!(
365 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()).unwrap_or_default()"
366 )
367 }
368 TypeRef::Named(_) => {
369 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect()).unwrap_or_default()")
370 }
371 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
372 let core_ty = core_prim_str(p);
373 format!(
374 "{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect()).unwrap_or_default()"
375 )
376 }
377 _ => format!("{name}: val.{name}.unwrap_or_default()"),
378 },
379 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
380 let k_is_json = matches!(k.as_ref(), TypeRef::Json);
384 let k_expr = if k_is_json {
385 "serde_json::from_str(&k).unwrap_or_default()"
386 } else {
387 "k.into()"
388 };
389 format!(
390 "{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()"
391 )
392 }
393 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
394 format!(
396 "{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (serde_json::from_str(&k).unwrap_or_default(), v)).collect()"
397 )
398 }
399 TypeRef::Map(k, v) => {
400 let has_named_val = matches!(v.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
402 let has_named_key = matches!(k.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
403 let val_is_string_enum = matches!(v.as_ref(), TypeRef::Named(n)
404 if config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)));
405 if field_is_ir_optional {
406 if val_is_string_enum {
408 format!(
409 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, serde_json::from_str(&v).unwrap_or_default())).collect())"
410 )
411 } else if has_named_val {
412 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
413 } else if has_named_key {
414 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
415 } else {
416 format!("{name}: val.{name}.map(|m| m.into_iter().collect())")
417 }
418 } else if val_is_string_enum {
419 format!(
420 "{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k, serde_json::from_str(&v).unwrap_or_default())).collect()"
421 )
422 } else if has_named_val {
423 format!("{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k, v.into())).collect()")
424 } else if has_named_key {
425 format!("{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k.into(), v)).collect()")
426 } else {
427 format!("{name}: val.{name}.unwrap_or_default().into_iter().collect()")
428 }
429 }
430 _ => {
431 format!("{name}: val.{name}.unwrap_or_default()")
433 }
434 }
435}
436
437pub fn field_conversion_to_core(name: &str, ty: &TypeRef, optional: bool) -> String {
439 match ty {
440 TypeRef::Primitive(_) | TypeRef::String | TypeRef::Unit => {
442 format!("{name}: val.{name}")
443 }
444 TypeRef::Bytes => {
449 if optional {
450 format!("{name}: val.{name}.map(|v| v.to_vec().into())")
451 } else {
452 format!("{name}: val.{name}.to_vec().into()")
453 }
454 }
455 TypeRef::Json => {
457 if optional {
458 format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())")
459 } else {
460 format!("{name}: serde_json::from_str(&val.{name}).unwrap_or_default()")
461 }
462 }
463 TypeRef::Char => {
465 if optional {
466 format!("{name}: val.{name}.and_then(|s| s.chars().next())")
467 } else {
468 format!("{name}: val.{name}.chars().next().unwrap_or('*')")
469 }
470 }
471 TypeRef::Duration => {
473 if optional {
474 format!("{name}: val.{name}.map(std::time::Duration::from_millis)")
475 } else {
476 format!("{name}: std::time::Duration::from_millis(val.{name})")
477 }
478 }
479 TypeRef::Path => {
481 if optional {
482 format!("{name}: val.{name}.map(Into::into)")
483 } else {
484 format!("{name}: val.{name}.into()")
485 }
486 }
487 TypeRef::Named(type_name) if is_tuple_type_name(type_name) => {
490 format!("{name}: val.{name}")
491 }
492 TypeRef::Named(_) => {
493 if optional {
494 format!("{name}: val.{name}.map(Into::into)")
495 } else {
496 format!("{name}: val.{name}.into()")
497 }
498 }
499 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
503 let k_expr = if matches!(k.as_ref(), TypeRef::Json) {
504 "serde_json::from_str(&k).unwrap_or_default()"
505 } else {
506 "k.into()"
507 };
508 if optional {
509 format!(
510 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect())"
511 )
512 } else {
513 format!(
514 "{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect()"
515 )
516 }
517 }
518 TypeRef::Optional(inner) => match inner.as_ref() {
520 TypeRef::Json => format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())"),
521 TypeRef::Named(_) | TypeRef::Path => format!("{name}: val.{name}.map(Into::into)"),
522 TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_)) => {
523 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
524 }
525 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
526 let k_expr = if matches!(k.as_ref(), TypeRef::Json) {
527 "serde_json::from_str(&k).unwrap_or_default()"
528 } else {
529 "k.into()"
530 };
531 format!(
532 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect())"
533 )
534 }
535 _ => format!("{name}: val.{name}"),
536 },
537 TypeRef::Vec(inner) => match inner.as_ref() {
539 TypeRef::Json => {
540 if optional {
541 format!(
542 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect())"
543 )
544 } else {
545 format!("{name}: val.{name}.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()")
546 }
547 }
548 TypeRef::Named(type_name) if is_tuple_type_name(type_name) => {
550 format!("{name}: val.{name}")
551 }
552 TypeRef::Named(_) => {
553 if optional {
554 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
555 } else {
556 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
557 }
558 }
559 _ => format!("{name}: val.{name}"),
560 },
561 TypeRef::Map(k, v) => {
564 let has_named_key = matches!(k.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
565 let has_named_val = matches!(v.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
566 let has_json_val = matches!(v.as_ref(), TypeRef::Json);
567 let has_json_key = matches!(k.as_ref(), TypeRef::Json);
568 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)));
570 let has_vec_json_val = matches!(v.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json));
572 if has_json_val || has_json_key || has_named_key || has_named_val || has_vec_named_val || has_vec_json_val {
573 let k_expr = if has_json_key {
577 "serde_json::from_str(&k).unwrap_or(serde_json::Value::String(k))"
578 } else {
579 "k.into()"
580 };
581 let v_expr = if has_json_val {
582 "serde_json::from_str(&v).unwrap_or(serde_json::Value::String(v))"
583 } else if has_named_val {
584 "v.into()"
585 } else if has_vec_named_val {
586 "v.into_iter().map(Into::into).collect()"
587 } else if has_vec_json_val {
588 "v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()"
589 } else {
590 "v"
591 };
592 if optional {
593 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, {v_expr})).collect())")
594 } else {
595 format!("{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, {v_expr})).collect()")
596 }
597 } else {
598 let is_string_map = matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String);
602 if is_string_map {
603 if optional {
604 format!(
605 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())"
606 )
607 } else {
608 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
609 }
610 } else {
611 if optional {
615 if has_named_val {
616 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
617 } else {
618 format!("{name}: val.{name}.map(|m| m.into_iter().collect())")
619 }
620 } else {
621 format!("{name}: val.{name}.into_iter().collect()")
622 }
623 }
624 }
625 }
626 }
627}
628
629pub fn field_conversion_to_core_cfg(name: &str, ty: &TypeRef, optional: bool, config: &ConversionConfig) -> String {
631 if optional && matches!(ty, TypeRef::Optional(_)) {
635 let inner_expr = field_conversion_to_core_cfg(name, ty, false, config);
638 if let Some(expr) = inner_expr.strip_prefix(&format!("{name}: ")) {
640 return format!("{name}: ({expr}).map(Some)");
641 }
642 return inner_expr;
643 }
644
645 if config.map_uses_jsvalue {
647 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
648 let is_vec_json = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json));
649 let is_map = matches!(ty, TypeRef::Map(_, _));
650 if is_nested_vec || is_map || is_vec_json {
651 if optional {
652 return format!(
653 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())"
654 );
655 }
656 return format!("{name}: serde_wasm_bindgen::from_value(val.{name}.clone()).unwrap_or_default()");
657 }
658 if let TypeRef::Optional(inner) = ty {
659 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
660 let is_inner_vec_json = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json));
661 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
662 if is_inner_nested || is_inner_map || is_inner_vec_json {
663 return format!(
664 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())"
665 );
666 }
667 }
668 }
669
670 if config.vec_named_to_string {
674 if let TypeRef::Vec(inner) = ty {
675 if matches!(inner.as_ref(), TypeRef::Named(_)) {
676 if optional {
677 return format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())");
678 }
679 return format!("{name}: serde_json::from_str(&val.{name}).unwrap_or_default()");
680 }
681 }
682 }
683 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
685 return format!("{name}: Default::default()");
686 }
687 if config.map_as_string {
688 if let TypeRef::Optional(inner) = ty {
689 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
690 return format!("{name}: Default::default()");
691 }
692 }
693 }
694 if config.json_to_string && matches!(ty, TypeRef::Json) {
696 return format!("{name}: Default::default()");
697 }
698 if config.json_as_value && matches!(ty, TypeRef::Json) {
700 return format!("{name}: val.{name}");
701 }
702 if config.json_as_value {
703 if let TypeRef::Optional(inner) = ty {
704 if matches!(inner.as_ref(), TypeRef::Json) {
705 return format!("{name}: val.{name}");
706 }
707 }
708 if let TypeRef::Vec(inner) = ty {
709 if matches!(inner.as_ref(), TypeRef::Json) {
710 if optional {
711 return format!("{name}: val.{name}.unwrap_or_default()");
712 }
713 return format!("{name}: val.{name}");
714 }
715 }
716 if let TypeRef::Map(_k, v) = ty {
717 if matches!(v.as_ref(), TypeRef::Json) {
718 if optional {
719 return format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())");
720 }
721 return format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v)).collect()");
722 }
723 }
724 }
725 if config.map_uses_jsvalue && matches!(ty, TypeRef::Json) {
727 if optional {
728 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())");
729 }
730 return format!("{name}: serde_wasm_bindgen::from_value(val.{name}.clone()).unwrap_or_default()");
731 }
732 if !config.cast_large_ints_to_i64
733 && !config.cast_large_ints_to_f64
734 && !config.cast_uints_to_i32
735 && !config.cast_f32_to_f64
736 && !config.json_to_string
737 && !config.vec_named_to_string
738 && !config.map_as_string
739 && config.from_binding_skip_types.is_empty()
740 {
741 return field_conversion_to_core(name, ty, optional);
742 }
743 match ty {
745 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
746 let core_ty = core_prim_str(p);
747 if optional {
748 format!("{name}: val.{name}.map(|v| v as {core_ty})")
749 } else {
750 format!("{name}: val.{name} as {core_ty}")
751 }
752 }
753 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
755 if optional {
756 format!("{name}: val.{name}.map(|v| v as f32)")
757 } else {
758 format!("{name}: val.{name} as f32")
759 }
760 }
761 TypeRef::Duration if config.cast_large_ints_to_i64 => {
762 if optional {
763 format!("{name}: val.{name}.map(|v| std::time::Duration::from_millis(v as u64))")
764 } else {
765 format!("{name}: std::time::Duration::from_millis(val.{name} as u64)")
766 }
767 }
768 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) => {
769 if let TypeRef::Primitive(p) = inner.as_ref() {
770 let core_ty = core_prim_str(p);
771 format!("{name}: val.{name}.map(|v| v as {core_ty})")
772 } else {
773 field_conversion_to_core(name, ty, optional)
774 }
775 }
776 TypeRef::Vec(inner)
778 if config.cast_large_ints_to_i64
779 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
780 {
781 if let TypeRef::Primitive(p) = inner.as_ref() {
782 let core_ty = core_prim_str(p);
783 if optional {
784 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
785 } else {
786 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
787 }
788 } else {
789 field_conversion_to_core(name, ty, optional)
790 }
791 }
792 TypeRef::Map(_k, v)
794 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
795 {
796 if let TypeRef::Primitive(p) = v.as_ref() {
797 let core_ty = core_prim_str(p);
798 if optional {
799 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
800 } else {
801 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
802 }
803 } else {
804 field_conversion_to_core(name, ty, optional)
805 }
806 }
807 TypeRef::Vec(inner)
809 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
810 {
811 if optional {
812 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
813 } else {
814 format!("{name}: val.{name}.into_iter().map(|v| v as f32).collect()")
815 }
816 }
817 TypeRef::Optional(inner)
819 if config.cast_f32_to_f64
820 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
821 {
822 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
823 }
824 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
826 let core_ty = core_prim_str(p);
827 if optional {
828 format!("{name}: val.{name}.map(|v| v as {core_ty})")
829 } else {
830 format!("{name}: val.{name} as {core_ty}")
831 }
832 }
833 TypeRef::Optional(inner)
835 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
836 {
837 if let TypeRef::Primitive(p) = inner.as_ref() {
838 let core_ty = core_prim_str(p);
839 format!("{name}: val.{name}.map(|v| v as {core_ty})")
840 } else {
841 field_conversion_to_core(name, ty, optional)
842 }
843 }
844 TypeRef::Vec(inner)
846 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
847 {
848 if let TypeRef::Primitive(p) = inner.as_ref() {
849 let core_ty = core_prim_str(p);
850 if optional {
851 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
852 } else {
853 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
854 }
855 } else {
856 field_conversion_to_core(name, ty, optional)
857 }
858 }
859 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
861 let core_ty = core_prim_str(p);
862 if optional {
863 format!("{name}: val.{name}.map(|v| v as {core_ty})")
864 } else {
865 format!("{name}: val.{name} as {core_ty}")
866 }
867 }
868 TypeRef::Optional(inner)
870 if config.cast_large_ints_to_f64
871 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
872 {
873 if let TypeRef::Primitive(p) = inner.as_ref() {
874 let core_ty = core_prim_str(p);
875 format!("{name}: val.{name}.map(|v| v as {core_ty})")
876 } else {
877 field_conversion_to_core(name, ty, optional)
878 }
879 }
880 TypeRef::Vec(inner)
882 if config.cast_large_ints_to_f64
883 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
884 {
885 if let TypeRef::Primitive(p) = inner.as_ref() {
886 let core_ty = core_prim_str(p);
887 if optional {
888 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
889 } else {
890 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
891 }
892 } else {
893 field_conversion_to_core(name, ty, optional)
894 }
895 }
896 TypeRef::Map(_k, v)
898 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
899 {
900 if let TypeRef::Primitive(p) = v.as_ref() {
901 let core_ty = core_prim_str(p);
902 if optional {
903 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
904 } else {
905 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
906 }
907 } else {
908 field_conversion_to_core(name, ty, optional)
909 }
910 }
911 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
914 format!("{name}: Default::default()")
915 }
916 TypeRef::Optional(inner) => match inner.as_ref() {
917 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
918 format!("{name}: Default::default()")
919 }
920 _ => field_conversion_to_core(name, ty, optional),
921 },
922 _ => field_conversion_to_core(name, ty, optional),
924 }
925}
926
927pub fn apply_core_wrapper_to_core(
930 conversion: &str,
931 name: &str,
932 core_wrapper: &CoreWrapper,
933 vec_inner_core_wrapper: &CoreWrapper,
934 optional: bool,
935) -> String {
936 if *vec_inner_core_wrapper == CoreWrapper::Arc {
938 return conversion
939 .replace(
940 ".map(Into::into).collect()",
941 ".map(|v| std::sync::Arc::new(v.into())).collect()",
942 )
943 .replace(
944 "map(|v| v.into_iter().map(Into::into)",
945 "map(|v| v.into_iter().map(|v| std::sync::Arc::new(v.into()))",
946 );
947 }
948
949 match core_wrapper {
950 CoreWrapper::None => conversion.to_string(),
951 CoreWrapper::Cow => {
952 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
956 if optional {
957 format!("{name}: {expr}.map(Into::into)")
958 } else if expr == format!("val.{name}") {
959 format!("{name}: val.{name}.into()")
960 } else if expr == "Default::default()" {
961 conversion.to_string()
964 } else {
965 format!("{name}: ({expr}).into()")
966 }
967 } else {
968 conversion.to_string()
969 }
970 }
971 CoreWrapper::Arc => {
972 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
974 if expr == "Default::default()" {
975 conversion.to_string()
978 } else if optional {
979 format!("{name}: {expr}.map(|v| std::sync::Arc::new(v))")
980 } else {
981 format!("{name}: std::sync::Arc::new({expr})")
982 }
983 } else {
984 conversion.to_string()
985 }
986 }
987 CoreWrapper::Bytes => {
988 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
994 let already_converted_non_opt =
995 expr == format!("val.{name}.into()") || expr == format!("val.{name}.to_vec().into()");
996 let already_converted_opt = expr
997 .strip_prefix(&format!("val.{name}"))
998 .map(|s| s == ".map(Into::into)" || s == ".map(|v| v.to_vec().into())")
999 .unwrap_or(false);
1000 if already_converted_non_opt || already_converted_opt {
1001 conversion.to_string()
1003 } else 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::ArcMutex => {
1019 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1021 if optional {
1022 format!("{name}: {expr}.map(|v| std::sync::Arc::new(std::sync::Mutex::new(v.into())))")
1023 } else if expr == format!("val.{name}") {
1024 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(val.{name}.into()))")
1025 } else {
1026 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(({expr}).into()))")
1027 }
1028 } else {
1029 conversion.to_string()
1030 }
1031 }
1032 }
1033}
1034
1035#[cfg(test)]
1036mod tests {
1037 use super::gen_from_binding_to_core;
1038 use alef_core::ir::{CoreWrapper, DefaultValue, FieldDef, TypeDef, TypeRef};
1039
1040 fn type_with_field(field: FieldDef) -> TypeDef {
1041 TypeDef {
1042 name: "ProcessConfig".to_string(),
1043 rust_path: "crate::ProcessConfig".to_string(),
1044 original_rust_path: String::new(),
1045 fields: vec![field],
1046 methods: vec![],
1047 is_opaque: false,
1048 is_clone: true,
1049 is_copy: false,
1050 doc: String::new(),
1051 cfg: None,
1052 is_trait: false,
1053 has_default: true,
1054 has_stripped_cfg_fields: false,
1055 is_return_type: false,
1056 serde_rename_all: None,
1057 has_serde: true,
1058 super_traits: vec![],
1059 }
1060 }
1061
1062 #[test]
1063 fn sanitized_cow_string_field_converts_to_core() {
1064 let field = FieldDef {
1065 name: "language".to_string(),
1066 ty: TypeRef::String,
1067 optional: false,
1068 default: None,
1069 doc: String::new(),
1070 sanitized: true,
1071 is_boxed: false,
1072 type_rust_path: None,
1073 cfg: None,
1074 typed_default: Some(DefaultValue::Empty),
1075 core_wrapper: CoreWrapper::Cow,
1076 vec_inner_core_wrapper: CoreWrapper::None,
1077 newtype_wrapper: None,
1078 serde_rename: None,
1079 };
1080
1081 let out = gen_from_binding_to_core(&type_with_field(field), "crate");
1082
1083 assert!(out.contains("language: val.language.into()"));
1084 assert!(!out.contains("language: Default::default()"));
1085 }
1086}