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 let Some(untagged_names) = config.untagged_data_enum_names {
697 let direct_named = matches!(ty, TypeRef::Named(n) if untagged_names.contains(n));
698 let optional_named = matches!(ty, TypeRef::Optional(inner)
699 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
700 let vec_named = matches!(ty, TypeRef::Vec(inner)
701 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
702 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
703 if matches!(outer.as_ref(), TypeRef::Vec(inner)
704 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n))));
705 if direct_named {
706 if optional {
707 return format!("{name}: val.{name}.and_then(|v| serde_json::from_value(v).ok())");
708 }
709 return format!("{name}: serde_json::from_value(val.{name}).unwrap_or_default()");
710 }
711 if optional_named {
712 return format!("{name}: val.{name}.and_then(|v| serde_json::from_value(v).ok())");
713 }
714 if vec_named {
715 if optional {
716 return format!(
717 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|x| serde_json::from_value(x).ok()).collect())"
718 );
719 }
720 return format!("{name}: val.{name}.into_iter().filter_map(|x| serde_json::from_value(x).ok()).collect()");
721 }
722 if optional_vec_named {
723 return format!(
724 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|x| serde_json::from_value(x).ok()).collect())"
725 );
726 }
727 }
728 if config.json_to_string && matches!(ty, TypeRef::Json) {
730 return format!("{name}: Default::default()");
731 }
732 if config.json_as_value && matches!(ty, TypeRef::Json) {
734 return format!("{name}: val.{name}");
735 }
736 if config.json_as_value {
737 if let TypeRef::Optional(inner) = ty {
738 if matches!(inner.as_ref(), TypeRef::Json) {
739 return format!("{name}: val.{name}");
740 }
741 }
742 if let TypeRef::Vec(inner) = ty {
743 if matches!(inner.as_ref(), TypeRef::Json) {
744 if optional {
745 return format!("{name}: val.{name}.unwrap_or_default()");
746 }
747 return format!("{name}: val.{name}");
748 }
749 }
750 if let TypeRef::Map(_k, v) = ty {
751 if matches!(v.as_ref(), TypeRef::Json) {
752 if optional {
753 return format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())");
754 }
755 return format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v)).collect()");
756 }
757 }
758 }
759 if config.map_uses_jsvalue && matches!(ty, TypeRef::Json) {
761 if optional {
762 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())");
763 }
764 return format!("{name}: serde_wasm_bindgen::from_value(val.{name}.clone()).unwrap_or_default()");
765 }
766 if !config.cast_large_ints_to_i64
767 && !config.cast_large_ints_to_f64
768 && !config.cast_uints_to_i32
769 && !config.cast_f32_to_f64
770 && !config.json_to_string
771 && !config.vec_named_to_string
772 && !config.map_as_string
773 && config.from_binding_skip_types.is_empty()
774 {
775 return field_conversion_to_core(name, ty, optional);
776 }
777 match ty {
779 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
780 let core_ty = core_prim_str(p);
781 if optional {
782 format!("{name}: val.{name}.map(|v| v as {core_ty})")
783 } else {
784 format!("{name}: val.{name} as {core_ty}")
785 }
786 }
787 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
789 if optional {
790 format!("{name}: val.{name}.map(|v| v as f32)")
791 } else {
792 format!("{name}: val.{name} as f32")
793 }
794 }
795 TypeRef::Duration if config.cast_large_ints_to_i64 => {
796 if optional {
797 format!("{name}: val.{name}.map(|v| std::time::Duration::from_millis(v as u64))")
798 } else {
799 format!("{name}: std::time::Duration::from_millis(val.{name} as u64)")
800 }
801 }
802 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) => {
803 if let TypeRef::Primitive(p) = inner.as_ref() {
804 let core_ty = core_prim_str(p);
805 format!("{name}: val.{name}.map(|v| v as {core_ty})")
806 } else {
807 field_conversion_to_core(name, ty, optional)
808 }
809 }
810 TypeRef::Vec(inner)
812 if config.cast_large_ints_to_i64
813 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
814 {
815 if let TypeRef::Primitive(p) = inner.as_ref() {
816 let core_ty = core_prim_str(p);
817 if optional {
818 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
819 } else {
820 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
821 }
822 } else {
823 field_conversion_to_core(name, ty, optional)
824 }
825 }
826 TypeRef::Map(_k, v)
828 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
829 {
830 if let TypeRef::Primitive(p) = v.as_ref() {
831 let core_ty = core_prim_str(p);
832 if optional {
833 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
834 } else {
835 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
836 }
837 } else {
838 field_conversion_to_core(name, ty, optional)
839 }
840 }
841 TypeRef::Vec(inner)
843 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
844 {
845 if optional {
846 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
847 } else {
848 format!("{name}: val.{name}.into_iter().map(|v| v as f32).collect()")
849 }
850 }
851 TypeRef::Optional(inner)
853 if config.cast_f32_to_f64
854 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
855 {
856 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
857 }
858 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
860 let core_ty = core_prim_str(p);
861 if optional {
862 format!("{name}: val.{name}.map(|v| v as {core_ty})")
863 } else {
864 format!("{name}: val.{name} as {core_ty}")
865 }
866 }
867 TypeRef::Optional(inner)
869 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
870 {
871 if let TypeRef::Primitive(p) = inner.as_ref() {
872 let core_ty = core_prim_str(p);
873 format!("{name}: val.{name}.map(|v| v as {core_ty})")
874 } else {
875 field_conversion_to_core(name, ty, optional)
876 }
877 }
878 TypeRef::Vec(inner)
880 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
881 {
882 if let TypeRef::Primitive(p) = inner.as_ref() {
883 let core_ty = core_prim_str(p);
884 if optional {
885 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
886 } else {
887 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
888 }
889 } else {
890 field_conversion_to_core(name, ty, optional)
891 }
892 }
893 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
895 let core_ty = core_prim_str(p);
896 if optional {
897 format!("{name}: val.{name}.map(|v| v as {core_ty})")
898 } else {
899 format!("{name}: val.{name} as {core_ty}")
900 }
901 }
902 TypeRef::Optional(inner)
904 if config.cast_large_ints_to_f64
905 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
906 {
907 if let TypeRef::Primitive(p) = inner.as_ref() {
908 let core_ty = core_prim_str(p);
909 format!("{name}: val.{name}.map(|v| v as {core_ty})")
910 } else {
911 field_conversion_to_core(name, ty, optional)
912 }
913 }
914 TypeRef::Vec(inner)
916 if config.cast_large_ints_to_f64
917 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
918 {
919 if let TypeRef::Primitive(p) = inner.as_ref() {
920 let core_ty = core_prim_str(p);
921 if optional {
922 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
923 } else {
924 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
925 }
926 } else {
927 field_conversion_to_core(name, ty, optional)
928 }
929 }
930 TypeRef::Map(_k, v)
932 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
933 {
934 if let TypeRef::Primitive(p) = v.as_ref() {
935 let core_ty = core_prim_str(p);
936 if optional {
937 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
938 } else {
939 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
940 }
941 } else {
942 field_conversion_to_core(name, ty, optional)
943 }
944 }
945 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
948 format!("{name}: Default::default()")
949 }
950 TypeRef::Optional(inner) => match inner.as_ref() {
951 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
952 format!("{name}: Default::default()")
953 }
954 _ => field_conversion_to_core(name, ty, optional),
955 },
956 _ => field_conversion_to_core(name, ty, optional),
958 }
959}
960
961pub fn apply_core_wrapper_to_core(
964 conversion: &str,
965 name: &str,
966 core_wrapper: &CoreWrapper,
967 vec_inner_core_wrapper: &CoreWrapper,
968 optional: bool,
969) -> String {
970 if *vec_inner_core_wrapper == CoreWrapper::Arc {
972 return conversion
973 .replace(
974 ".map(Into::into).collect()",
975 ".map(|v| std::sync::Arc::new(v.into())).collect()",
976 )
977 .replace(
978 "map(|v| v.into_iter().map(Into::into)",
979 "map(|v| v.into_iter().map(|v| std::sync::Arc::new(v.into()))",
980 );
981 }
982
983 match core_wrapper {
984 CoreWrapper::None => conversion.to_string(),
985 CoreWrapper::Cow => {
986 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
990 if optional {
991 format!("{name}: {expr}.map(Into::into)")
992 } else if expr == format!("val.{name}") {
993 format!("{name}: val.{name}.into()")
994 } else if expr == "Default::default()" {
995 conversion.to_string()
998 } else {
999 format!("{name}: ({expr}).into()")
1000 }
1001 } else {
1002 conversion.to_string()
1003 }
1004 }
1005 CoreWrapper::Arc => {
1006 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1008 if expr == "Default::default()" {
1009 conversion.to_string()
1012 } else if optional {
1013 format!("{name}: {expr}.map(|v| std::sync::Arc::new(v))")
1014 } else {
1015 format!("{name}: std::sync::Arc::new({expr})")
1016 }
1017 } else {
1018 conversion.to_string()
1019 }
1020 }
1021 CoreWrapper::Bytes => {
1022 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1028 let already_converted_non_opt =
1029 expr == format!("val.{name}.into()") || expr == format!("val.{name}.to_vec().into()");
1030 let already_converted_opt = expr
1031 .strip_prefix(&format!("val.{name}"))
1032 .map(|s| s == ".map(Into::into)" || s == ".map(|v| v.to_vec().into())")
1033 .unwrap_or(false);
1034 if already_converted_non_opt || already_converted_opt {
1035 conversion.to_string()
1037 } else if optional {
1038 format!("{name}: {expr}.map(Into::into)")
1039 } else if expr == format!("val.{name}") {
1040 format!("{name}: val.{name}.into()")
1041 } else if expr == "Default::default()" {
1042 conversion.to_string()
1045 } else {
1046 format!("{name}: ({expr}).into()")
1047 }
1048 } else {
1049 conversion.to_string()
1050 }
1051 }
1052 CoreWrapper::ArcMutex => {
1053 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1055 if optional {
1056 format!("{name}: {expr}.map(|v| std::sync::Arc::new(std::sync::Mutex::new(v.into())))")
1057 } else if expr == format!("val.{name}") {
1058 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(val.{name}.into()))")
1059 } else {
1060 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(({expr}).into()))")
1061 }
1062 } else {
1063 conversion.to_string()
1064 }
1065 }
1066 }
1067}
1068
1069#[cfg(test)]
1070mod tests {
1071 use super::gen_from_binding_to_core;
1072 use alef_core::ir::{CoreWrapper, DefaultValue, FieldDef, TypeDef, TypeRef};
1073
1074 fn type_with_field(field: FieldDef) -> TypeDef {
1075 TypeDef {
1076 name: "ProcessConfig".to_string(),
1077 rust_path: "crate::ProcessConfig".to_string(),
1078 original_rust_path: String::new(),
1079 fields: vec![field],
1080 methods: vec![],
1081 is_opaque: false,
1082 is_clone: true,
1083 is_copy: false,
1084 doc: String::new(),
1085 cfg: None,
1086 is_trait: false,
1087 has_default: true,
1088 has_stripped_cfg_fields: false,
1089 is_return_type: false,
1090 serde_rename_all: None,
1091 has_serde: true,
1092 super_traits: vec![],
1093 }
1094 }
1095
1096 #[test]
1097 fn sanitized_cow_string_field_converts_to_core() {
1098 let field = FieldDef {
1099 name: "language".to_string(),
1100 ty: TypeRef::String,
1101 optional: false,
1102 default: None,
1103 doc: String::new(),
1104 sanitized: true,
1105 is_boxed: false,
1106 type_rust_path: None,
1107 cfg: None,
1108 typed_default: Some(DefaultValue::Empty),
1109 core_wrapper: CoreWrapper::Cow,
1110 vec_inner_core_wrapper: CoreWrapper::None,
1111 newtype_wrapper: None,
1112 serde_rename: None,
1113 };
1114
1115 let out = gen_from_binding_to_core(&type_with_field(field), "crate");
1116
1117 assert!(out.contains("language: val.language.into()"));
1118 assert!(!out.contains("language: Default::default()"));
1119 }
1120}