1use alef_core::ir::{CoreWrapper, PrimitiveType, TypeDef, TypeRef};
2
3use super::ConversionConfig;
4use super::helpers::{
5 core_prim_str, core_type_path_remapped, is_newtype, is_tuple_type_name, needs_f64_cast, needs_i32_cast,
6 needs_i64_cast,
7};
8
9pub fn gen_from_binding_to_core(typ: &TypeDef, core_import: &str) -> String {
13 gen_from_binding_to_core_cfg(typ, core_import, &ConversionConfig::default())
14}
15
16pub fn gen_from_binding_to_core_cfg(typ: &TypeDef, core_import: &str, config: &ConversionConfig) -> String {
18 let core_path = core_type_path_remapped(typ, core_import, config.source_crate_remaps);
19 let binding_name = format!("{}{}", config.type_name_prefix, typ.name);
20
21 if is_newtype(typ) {
23 let field = &typ.fields[0];
24 let newtype_inner_expr = match &field.ty {
25 TypeRef::Named(_) => "val._0.into()".to_string(),
26 TypeRef::Path => "val._0.into()".to_string(),
27 TypeRef::Duration => "std::time::Duration::from_millis(val._0)".to_string(),
28 _ => "val._0".to_string(),
29 };
30 return crate::template_env::render(
31 "conversions/binding_to_core_impl",
32 minijinja::context! {
33 core_path => core_path,
34 binding_name => binding_name,
35 is_newtype => true,
36 newtype_inner_expr => newtype_inner_expr,
37 builder_mode => false,
38 uses_builder_pattern => false,
39 has_stripped_cfg_fields => typ.has_stripped_cfg_fields,
40 statements => vec![] as Vec<String>,
41 fields => vec![] as Vec<String>,
42 },
43 );
44 }
45
46 let uses_builder_pattern = (config.option_duration_on_defaults
48 && typ.has_default
49 && typ
50 .fields
51 .iter()
52 .any(|f| !f.optional && matches!(f.ty, TypeRef::Duration)))
53 || (config.optionalize_defaults && typ.has_default);
54
55 let has_optionalized_duration = config.option_duration_on_defaults
60 && typ.has_default
61 && typ
62 .fields
63 .iter()
64 .any(|f| !f.optional && matches!(f.ty, TypeRef::Duration));
65
66 if has_optionalized_duration {
67 let optionalized = config.optionalize_defaults && typ.has_default;
69 let mut statements = Vec::new();
70 for field in &typ.fields {
71 if field.sanitized && field.core_wrapper != CoreWrapper::Cow {
72 continue;
74 }
75 if !config.exclude_types.is_empty()
77 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types)
78 {
79 continue;
80 }
81 let binding_name_field = config.binding_field_name_owned(&typ.name, &field.name);
83 if !field.optional && matches!(field.ty, TypeRef::Duration) {
84 let cast = if config.cast_large_ints_to_i64 { " as u64" } else { "" };
85 statements.push(format!(
86 "if let Some(__v) = val.{binding_name_field} {{ __result.{} = std::time::Duration::from_millis(__v{cast}); }}",
87 field.name
88 ));
89 continue;
90 }
91 let conversion = if optionalized && !field.optional {
92 gen_optionalized_field_to_core(&field.name, &field.ty, config, false)
95 } else {
96 field_conversion_to_core_cfg(&field.name, &field.ty, field.optional, config)
102 };
103 let conversion = if binding_name_field != field.name {
105 conversion.replace(&format!("val.{}", field.name), &format!("val.{binding_name_field}"))
106 } else {
107 conversion
108 };
109 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
111 statements.push(format!("__result.{} = {};", field.name, expr));
112 }
113 }
114
115 return crate::template_env::render(
116 "conversions/binding_to_core_impl",
117 minijinja::context! {
118 core_path => core_path,
119 binding_name => binding_name,
120 is_newtype => false,
121 newtype_inner_expr => "",
122 builder_mode => true,
123 uses_builder_pattern => uses_builder_pattern,
124 has_stripped_cfg_fields => typ.has_stripped_cfg_fields,
125 statements => statements,
126 fields => vec![] as Vec<String>,
127 },
128 );
129 }
130
131 let optionalized = config.optionalize_defaults && typ.has_default;
132
133 let mut fields = Vec::new();
135 let mut statements = Vec::new();
136
137 for field in &typ.fields {
138 let references_excluded = !config.exclude_types.is_empty()
150 && super::helpers::field_references_excluded_type(&field.ty, config.exclude_types);
151 if references_excluded && typ.has_stripped_cfg_fields {
152 continue;
153 }
154 if field.cfg.is_some()
160 && !config.never_skip_cfg_field_names.contains(&field.name)
161 && config.strip_cfg_fields_from_binding_struct
162 {
163 continue;
164 }
165 if optionalized && ((field.sanitized && field.core_wrapper != CoreWrapper::Cow) || references_excluded) {
166 continue;
167 }
168 let field_was_optionalized = optionalized && !field.optional;
169 let conversion = if (field.sanitized && field.core_wrapper != CoreWrapper::Cow) || references_excluded {
170 format!("{}: Default::default()", field.name)
171 } else if field_was_optionalized {
172 field_conversion_to_core_cfg(&field.name, &field.ty, false, config)
175 } else {
176 field_conversion_to_core_cfg(&field.name, &field.ty, field.optional, config)
177 };
178 let conversion = if let Some(newtype_path) = &field.newtype_wrapper {
184 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
185 match &field.ty {
188 TypeRef::Optional(_) => format!("{}: ({expr}).map({newtype_path})", field.name),
189 TypeRef::Vec(_) => {
190 let inner_expr = if let Some(prefix) = expr.strip_suffix(".collect()") {
195 format!("{prefix}.collect::<Vec<_>>()")
196 } else {
197 expr.to_string()
198 };
199 format!(
200 "{}: ({inner_expr}).into_iter().map({newtype_path}).collect()",
201 field.name
202 )
203 }
204 _ if field.optional => format!("{}: ({expr}).map({newtype_path})", field.name),
205 _ => format!("{}: {newtype_path}({expr})", field.name),
206 }
207 } else {
208 conversion
209 }
210 } else {
211 conversion
212 };
213 let conversion = if field.is_boxed && matches!(&field.ty, TypeRef::Named(_)) {
215 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
216 if field.optional {
217 format!("{}: {}.map(Box::new)", field.name, expr)
219 } else {
220 format!("{}: Box::new({})", field.name, expr)
221 }
222 } else {
223 conversion
224 }
225 } else {
226 conversion
227 };
228 let is_opaque_arc_field = field.core_wrapper == CoreWrapper::Arc
236 && matches!(&field.ty, TypeRef::Named(n) if config
237 .opaque_types
238 .is_some_and(|opaque| opaque.contains(n.as_str())));
239 let is_opaque_no_wrapper_field = field.core_wrapper == CoreWrapper::None
243 && matches!(&field.ty, TypeRef::Named(n) if config
244 .opaque_types
245 .is_some_and(|opaque| opaque.contains(n.as_str())));
246 let conversion = if is_opaque_arc_field {
247 if field.optional {
248 format!("{}: val.{}.map(|v| v.inner)", field.name, field.name)
249 } else {
250 format!("{}: val.{}.inner", field.name, field.name)
251 }
252 } else if is_opaque_no_wrapper_field {
253 format!("{}: Default::default()", field.name)
254 } else {
255 apply_core_wrapper_to_core(
256 &conversion,
257 &field.name,
258 &field.core_wrapper,
259 &field.vec_inner_core_wrapper,
260 field.optional,
261 )
262 };
263 let binding_name_field = config.binding_field_name_owned(&typ.name, &field.name);
267 let conversion = if binding_name_field != field.name {
268 conversion.replace(&format!("val.{}", field.name), &format!("val.{binding_name_field}"))
269 } else {
270 conversion
271 };
272 if optionalized {
273 if let Some(expr) = conversion.strip_prefix(&format!("{}: ", field.name)) {
274 if field_was_optionalized {
275 statements.push(format!(
276 "if let Some(__v) = val.{binding_name_field} {{ __result.{} = {}; }}",
277 field.name,
278 expr.replace(&format!("val.{binding_name_field}"), "__v")
279 ));
280 } else {
281 statements.push(format!("__result.{} = {};", field.name, expr));
282 }
283 }
284 } else {
285 fields.push(conversion);
286 }
287 }
288
289 crate::template_env::render(
293 "conversions/binding_to_core_impl",
294 minijinja::context! {
295 core_path => core_path,
296 binding_name => binding_name,
297 is_newtype => false,
298 newtype_inner_expr => "",
299 builder_mode => optionalized,
300 uses_builder_pattern => uses_builder_pattern,
301 has_stripped_cfg_fields => typ.has_stripped_cfg_fields,
302 statements => statements,
303 fields => fields,
304 },
305 )
306}
307
308pub(super) fn gen_optionalized_field_to_core(
313 name: &str,
314 ty: &TypeRef,
315 config: &ConversionConfig,
316 field_is_ir_optional: bool,
317) -> String {
318 match ty {
319 TypeRef::Json if config.json_as_value => {
320 format!("{name}: val.{name}.unwrap_or_default()")
321 }
322 TypeRef::Json => {
323 format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok()).unwrap_or_default()")
324 }
325 TypeRef::Named(_) => {
326 format!("{name}: val.{name}.map(Into::into).unwrap_or_default()")
328 }
329 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
330 format!("{name}: val.{name}.map(|v| v as f32).unwrap_or(0.0)")
331 }
332 TypeRef::Primitive(PrimitiveType::F32 | PrimitiveType::F64) => {
333 format!("{name}: val.{name}.unwrap_or(0.0)")
334 }
335 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
336 let core_ty = core_prim_str(p);
337 format!("{name}: val.{name}.map(|v| v as {core_ty}).unwrap_or_default()")
338 }
339 TypeRef::Optional(inner)
340 if config.cast_large_ints_to_i64
341 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
342 {
343 if let TypeRef::Primitive(p) = inner.as_ref() {
344 let core_ty = core_prim_str(p);
345 format!("{name}: val.{name}.map(|v| v as {core_ty})")
346 } else {
347 field_conversion_to_core(name, ty, false)
348 }
349 }
350 TypeRef::Duration if config.cast_large_ints_to_i64 => {
351 format!("{name}: val.{name}.map(|v| std::time::Duration::from_millis(v as u64)).unwrap_or_default()")
352 }
353 TypeRef::Duration => {
354 format!("{name}: val.{name}.map(std::time::Duration::from_millis).unwrap_or_default()")
355 }
356 TypeRef::Path => {
357 format!("{name}: val.{name}.map(Into::into).unwrap_or_default()")
358 }
359 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Path) => {
360 format!("{name}: val.{name}.map(|s| std::path::PathBuf::from(s))")
362 }
363 TypeRef::Optional(_) => {
364 format!("{name}: val.{name}.map(Some)")
367 }
368 TypeRef::Char => {
370 format!("{name}: val.{name}.and_then(|s| s.chars().next()).unwrap_or('*')")
371 }
372 TypeRef::Vec(inner) => match inner.as_ref() {
373 TypeRef::Json => {
374 format!(
375 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()).unwrap_or_default()"
376 )
377 }
378 TypeRef::Named(_) => {
379 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect()).unwrap_or_default()")
380 }
381 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
382 let core_ty = core_prim_str(p);
383 format!(
384 "{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect()).unwrap_or_default()"
385 )
386 }
387 _ => format!("{name}: val.{name}.unwrap_or_default()"),
388 },
389 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
390 let k_is_json = matches!(k.as_ref(), TypeRef::Json);
394 let k_expr = if k_is_json {
395 "serde_json::from_str(&k).unwrap_or_default()"
396 } else {
397 "k.into()"
398 };
399 format!(
400 "{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()"
401 )
402 }
403 TypeRef::Map(k, _v) if matches!(k.as_ref(), TypeRef::Json) => {
404 format!(
406 "{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (serde_json::from_str(&k).unwrap_or_default(), v)).collect()"
407 )
408 }
409 TypeRef::Map(k, v) => {
410 let has_named_val = matches!(v.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
412 let has_named_key = matches!(k.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
413 let val_is_string_enum = matches!(v.as_ref(), TypeRef::Named(n)
414 if config.enum_string_names.as_ref().is_some_and(|names| names.contains(n)));
415 if field_is_ir_optional {
416 if val_is_string_enum {
418 format!(
419 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, serde_json::from_str(&v).unwrap_or_default())).collect())"
420 )
421 } else if has_named_val {
422 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
423 } else if has_named_key {
424 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())")
425 } else {
426 format!("{name}: val.{name}.map(|m| m.into_iter().collect())")
427 }
428 } else if val_is_string_enum {
429 format!(
430 "{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k, serde_json::from_str(&v).unwrap_or_default())).collect()"
431 )
432 } else if has_named_val {
433 format!("{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k, v.into())).collect()")
434 } else if has_named_key {
435 format!("{name}: val.{name}.unwrap_or_default().into_iter().map(|(k, v)| (k.into(), v)).collect()")
436 } else {
437 format!("{name}: val.{name}.unwrap_or_default().into_iter().collect()")
438 }
439 }
440 _ => {
441 format!("{name}: val.{name}.unwrap_or_default()")
443 }
444 }
445}
446
447pub fn field_conversion_to_core(name: &str, ty: &TypeRef, optional: bool) -> String {
449 match ty {
450 TypeRef::Primitive(_) | TypeRef::String | TypeRef::Unit => {
452 format!("{name}: val.{name}")
453 }
454 TypeRef::Bytes => {
459 if optional {
460 format!("{name}: val.{name}.map(|v| v.to_vec().into())")
461 } else {
462 format!("{name}: val.{name}.to_vec().into()")
463 }
464 }
465 TypeRef::Json => {
467 if optional {
468 format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())")
469 } else {
470 format!("{name}: serde_json::from_str(&val.{name}).unwrap_or_default()")
471 }
472 }
473 TypeRef::Char => {
475 if optional {
476 format!("{name}: val.{name}.and_then(|s| s.chars().next())")
477 } else {
478 format!("{name}: val.{name}.chars().next().unwrap_or('*')")
479 }
480 }
481 TypeRef::Duration => {
483 if optional {
484 format!("{name}: val.{name}.map(std::time::Duration::from_millis)")
485 } else {
486 format!("{name}: std::time::Duration::from_millis(val.{name})")
487 }
488 }
489 TypeRef::Path => {
491 if optional {
492 format!("{name}: val.{name}.map(Into::into)")
493 } else {
494 format!("{name}: val.{name}.into()")
495 }
496 }
497 TypeRef::Named(type_name) if is_tuple_type_name(type_name) => {
500 format!("{name}: val.{name}")
501 }
502 TypeRef::Named(_) => {
503 if optional {
504 format!("{name}: val.{name}.map(Into::into)")
505 } else {
506 format!("{name}: val.{name}.into()")
507 }
508 }
509 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
513 let k_expr = if matches!(k.as_ref(), TypeRef::Json) {
514 "serde_json::from_str(&k).unwrap_or_default()"
515 } else {
516 "k.into()"
517 };
518 if optional {
519 format!(
520 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect())"
521 )
522 } else {
523 format!(
524 "{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect()"
525 )
526 }
527 }
528 TypeRef::Map(_k, v) if matches!(v.as_ref(), TypeRef::Bytes) => {
531 if optional {
532 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect())")
533 } else {
534 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v.to_vec().into())).collect()")
535 }
536 }
537 TypeRef::Optional(inner) => match inner.as_ref() {
539 TypeRef::Json => format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())"),
540 TypeRef::Named(_) | TypeRef::Path => format!("{name}: val.{name}.map(Into::into)"),
541 TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Named(_)) => {
542 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
543 }
544 TypeRef::Map(k, v) if matches!(v.as_ref(), TypeRef::Json) => {
545 let k_expr = if matches!(k.as_ref(), TypeRef::Json) {
546 "serde_json::from_str(&k).unwrap_or_default()"
547 } else {
548 "k.into()"
549 };
550 format!(
551 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, serde_json::from_str(&v).unwrap_or_default())).collect())"
552 )
553 }
554 _ => format!("{name}: val.{name}"),
555 },
556 TypeRef::Vec(inner) => match inner.as_ref() {
558 TypeRef::Json => {
559 if optional {
560 format!(
561 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect())"
562 )
563 } else {
564 format!("{name}: val.{name}.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()")
565 }
566 }
567 TypeRef::Named(type_name) if is_tuple_type_name(type_name) => {
569 format!("{name}: val.{name}")
570 }
571 TypeRef::Named(_) => {
572 if optional {
573 format!("{name}: val.{name}.map(|v| v.into_iter().map(Into::into).collect())")
574 } else {
575 format!("{name}: val.{name}.into_iter().map(Into::into).collect()")
576 }
577 }
578 _ => format!("{name}: val.{name}"),
579 },
580 TypeRef::Map(k, v) => {
583 let has_named_key = matches!(k.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
584 let has_named_val = matches!(v.as_ref(), TypeRef::Named(n) if !is_tuple_type_name(n));
585 let has_json_val = matches!(v.as_ref(), TypeRef::Json);
586 let has_json_key = matches!(k.as_ref(), TypeRef::Json);
587 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)));
589 let has_vec_json_val = matches!(v.as_ref(), TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json));
591 if has_json_val || has_json_key || has_named_key || has_named_val || has_vec_named_val || has_vec_json_val {
592 let k_expr = if has_json_key {
596 "serde_json::from_str(&k).unwrap_or(serde_json::Value::String(k))"
597 } else {
598 "k.into()"
599 };
600 let v_expr = if has_json_val {
601 "serde_json::from_str(&v).unwrap_or(serde_json::Value::String(v))"
602 } else if has_named_val {
603 "v.into()"
604 } else if has_vec_named_val {
605 "v.into_iter().map(Into::into).collect()"
606 } else if has_vec_json_val {
607 "v.into_iter().filter_map(|s| serde_json::from_str(&s).ok()).collect()"
608 } else {
609 "v"
610 };
611 if optional {
612 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| ({k_expr}, {v_expr})).collect())")
613 } else {
614 format!("{name}: val.{name}.into_iter().map(|(k, v)| ({k_expr}, {v_expr})).collect()")
615 }
616 } else {
617 let is_string_map = matches!(k.as_ref(), TypeRef::String) && matches!(v.as_ref(), TypeRef::String);
621 if is_string_map {
622 if optional {
623 format!(
624 "{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v.into())).collect())"
625 )
626 } else {
627 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v.into())).collect()")
628 }
629 } else {
630 if optional {
634 if has_named_val {
635 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect())")
636 } else {
637 format!("{name}: val.{name}.map(|m| m.into_iter().collect())")
638 }
639 } else {
640 format!("{name}: val.{name}.into_iter().collect()")
641 }
642 }
643 }
644 }
645 }
646}
647
648pub fn field_conversion_to_core_cfg(name: &str, ty: &TypeRef, optional: bool, config: &ConversionConfig) -> String {
650 if optional && matches!(ty, TypeRef::Optional(_)) {
654 let inner_expr = field_conversion_to_core_cfg(name, ty, false, config);
657 if let Some(expr) = inner_expr.strip_prefix(&format!("{name}: ")) {
659 return format!("{name}: ({expr}).map(Some)");
660 }
661 return inner_expr;
662 }
663
664 if config.map_uses_jsvalue {
666 let is_nested_vec = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Vec(_)));
667 let is_vec_json = matches!(ty, TypeRef::Vec(inner) if matches!(inner.as_ref(), TypeRef::Json));
668 let is_map = matches!(ty, TypeRef::Map(_, _));
669 if is_nested_vec || is_map || is_vec_json {
670 if optional {
671 return format!(
672 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())"
673 );
674 }
675 return format!("{name}: serde_wasm_bindgen::from_value(val.{name}.clone()).unwrap_or_default()");
676 }
677 if let TypeRef::Optional(inner) = ty {
678 let is_inner_nested = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Vec(_)));
679 let is_inner_vec_json = matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Json));
680 let is_inner_map = matches!(inner.as_ref(), TypeRef::Map(_, _));
681 if is_inner_nested || is_inner_map || is_inner_vec_json {
682 return format!(
683 "{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())"
684 );
685 }
686 }
687 }
688
689 if config.vec_named_to_string {
693 if let TypeRef::Vec(inner) = ty {
694 if matches!(inner.as_ref(), TypeRef::Named(_)) {
695 if optional {
696 return format!("{name}: val.{name}.as_ref().and_then(|s| serde_json::from_str(s).ok())");
697 }
698 return format!("{name}: serde_json::from_str(&val.{name}).unwrap_or_default()");
699 }
700 }
701 }
702 if config.map_as_string && matches!(ty, TypeRef::Map(_, _)) {
704 return format!("{name}: Default::default()");
705 }
706 if config.map_as_string {
707 if let TypeRef::Optional(inner) = ty {
708 if matches!(inner.as_ref(), TypeRef::Map(_, _)) {
709 return format!("{name}: Default::default()");
710 }
711 }
712 }
713 if let Some(untagged_names) = config.untagged_data_enum_names {
716 let direct_named = matches!(ty, TypeRef::Named(n) if untagged_names.contains(n));
717 let optional_named = matches!(ty, TypeRef::Optional(inner)
718 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
719 let vec_named = matches!(ty, TypeRef::Vec(inner)
720 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n)));
721 let optional_vec_named = matches!(ty, TypeRef::Optional(outer)
722 if matches!(outer.as_ref(), TypeRef::Vec(inner)
723 if matches!(inner.as_ref(), TypeRef::Named(n) if untagged_names.contains(n))));
724 if direct_named {
725 if optional {
726 return format!("{name}: val.{name}.and_then(|v| serde_json::from_value(v).ok())");
727 }
728 return format!("{name}: serde_json::from_value(val.{name}).unwrap_or_default()");
729 }
730 if optional_named {
731 return format!("{name}: val.{name}.and_then(|v| serde_json::from_value(v).ok())");
732 }
733 if vec_named {
734 if optional {
735 return format!(
736 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|x| serde_json::from_value(x).ok()).collect())"
737 );
738 }
739 return format!("{name}: val.{name}.into_iter().filter_map(|x| serde_json::from_value(x).ok()).collect()");
740 }
741 if optional_vec_named {
742 return format!(
743 "{name}: val.{name}.map(|v| v.into_iter().filter_map(|x| serde_json::from_value(x).ok()).collect())"
744 );
745 }
746 }
747 if config.json_to_string && matches!(ty, TypeRef::Json) {
749 return format!("{name}: Default::default()");
750 }
751 if config.json_as_value && matches!(ty, TypeRef::Json) {
753 return format!("{name}: val.{name}");
754 }
755 if config.json_as_value {
756 if let TypeRef::Optional(inner) = ty {
757 if matches!(inner.as_ref(), TypeRef::Json) {
758 return format!("{name}: val.{name}");
759 }
760 }
761 if let TypeRef::Vec(inner) = ty {
762 if matches!(inner.as_ref(), TypeRef::Json) {
763 if optional {
764 return format!("{name}: val.{name}.unwrap_or_default()");
765 }
766 return format!("{name}: val.{name}");
767 }
768 }
769 if let TypeRef::Map(_k, v) = ty {
770 if matches!(v.as_ref(), TypeRef::Json) {
771 if optional {
772 return format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k.into(), v)).collect())");
773 }
774 return format!("{name}: val.{name}.into_iter().map(|(k, v)| (k.into(), v)).collect()");
775 }
776 }
777 }
778 if config.map_uses_jsvalue && matches!(ty, TypeRef::Json) {
780 if optional {
781 return format!("{name}: val.{name}.as_ref().and_then(|v| serde_wasm_bindgen::from_value(v.clone()).ok())");
782 }
783 return format!("{name}: serde_wasm_bindgen::from_value(val.{name}.clone()).unwrap_or_default()");
784 }
785 if !config.cast_large_ints_to_i64
786 && !config.cast_large_ints_to_f64
787 && !config.cast_uints_to_i32
788 && !config.cast_f32_to_f64
789 && !config.json_to_string
790 && !config.vec_named_to_string
791 && !config.map_as_string
792 && config.from_binding_skip_types.is_empty()
793 {
794 return field_conversion_to_core(name, ty, optional);
795 }
796 match ty {
798 TypeRef::Primitive(p) if config.cast_large_ints_to_i64 && needs_i64_cast(p) => {
799 let core_ty = core_prim_str(p);
800 if optional {
801 format!("{name}: val.{name}.map(|v| v as {core_ty})")
802 } else {
803 format!("{name}: val.{name} as {core_ty}")
804 }
805 }
806 TypeRef::Primitive(PrimitiveType::F32) if config.cast_f32_to_f64 => {
808 if optional {
809 format!("{name}: val.{name}.map(|v| v as f32)")
810 } else {
811 format!("{name}: val.{name} as f32")
812 }
813 }
814 TypeRef::Duration if config.cast_large_ints_to_i64 => {
815 if optional {
816 format!("{name}: val.{name}.map(|v| std::time::Duration::from_millis(v as u64))")
817 } else {
818 format!("{name}: std::time::Duration::from_millis(val.{name} as u64)")
819 }
820 }
821 TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) => {
822 if let TypeRef::Primitive(p) = inner.as_ref() {
823 let core_ty = core_prim_str(p);
824 format!("{name}: val.{name}.map(|v| v as {core_ty})")
825 } else {
826 field_conversion_to_core(name, ty, optional)
827 }
828 }
829 TypeRef::Vec(inner)
831 if config.cast_large_ints_to_i64
832 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
833 {
834 if let TypeRef::Primitive(p) = inner.as_ref() {
835 let core_ty = core_prim_str(p);
836 if optional {
837 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
838 } else {
839 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
840 }
841 } else {
842 field_conversion_to_core(name, ty, optional)
843 }
844 }
845 TypeRef::Map(_k, v)
847 if config.cast_large_ints_to_i64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_i64_cast(p)) =>
848 {
849 if let TypeRef::Primitive(p) = v.as_ref() {
850 let core_ty = core_prim_str(p);
851 if optional {
852 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
853 } else {
854 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
855 }
856 } else {
857 field_conversion_to_core(name, ty, optional)
858 }
859 }
860 TypeRef::Vec(inner)
862 if config.cast_f32_to_f64 && matches!(inner.as_ref(), TypeRef::Primitive(PrimitiveType::F32)) =>
863 {
864 if optional {
865 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
866 } else {
867 format!("{name}: val.{name}.into_iter().map(|v| v as f32).collect()")
868 }
869 }
870 TypeRef::Optional(inner)
872 if config.cast_f32_to_f64
873 && matches!(inner.as_ref(), TypeRef::Vec(vi) if matches!(vi.as_ref(), TypeRef::Primitive(PrimitiveType::F32))) =>
874 {
875 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as f32).collect())")
876 }
877 TypeRef::Primitive(p) if config.cast_uints_to_i32 && needs_i32_cast(p) => {
879 let core_ty = core_prim_str(p);
880 if optional {
881 format!("{name}: val.{name}.map(|v| v as {core_ty})")
882 } else {
883 format!("{name}: val.{name} as {core_ty}")
884 }
885 }
886 TypeRef::Optional(inner)
888 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
889 {
890 if let TypeRef::Primitive(p) = inner.as_ref() {
891 let core_ty = core_prim_str(p);
892 format!("{name}: val.{name}.map(|v| v as {core_ty})")
893 } else {
894 field_conversion_to_core(name, ty, optional)
895 }
896 }
897 TypeRef::Vec(inner)
899 if config.cast_uints_to_i32 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_i32_cast(p)) =>
900 {
901 if let TypeRef::Primitive(p) = inner.as_ref() {
902 let core_ty = core_prim_str(p);
903 if optional {
904 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
905 } else {
906 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
907 }
908 } else {
909 field_conversion_to_core(name, ty, optional)
910 }
911 }
912 TypeRef::Primitive(p) if config.cast_large_ints_to_f64 && needs_f64_cast(p) => {
914 let core_ty = core_prim_str(p);
915 if optional {
916 format!("{name}: val.{name}.map(|v| v as {core_ty})")
917 } else {
918 format!("{name}: val.{name} as {core_ty}")
919 }
920 }
921 TypeRef::Optional(inner)
923 if config.cast_large_ints_to_f64
924 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
925 {
926 if let TypeRef::Primitive(p) = inner.as_ref() {
927 let core_ty = core_prim_str(p);
928 format!("{name}: val.{name}.map(|v| v as {core_ty})")
929 } else {
930 field_conversion_to_core(name, ty, optional)
931 }
932 }
933 TypeRef::Vec(inner)
935 if config.cast_large_ints_to_f64
936 && matches!(inner.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
937 {
938 if let TypeRef::Primitive(p) = inner.as_ref() {
939 let core_ty = core_prim_str(p);
940 if optional {
941 format!("{name}: val.{name}.map(|v| v.into_iter().map(|x| x as {core_ty}).collect())")
942 } else {
943 format!("{name}: val.{name}.into_iter().map(|v| v as {core_ty}).collect()")
944 }
945 } else {
946 field_conversion_to_core(name, ty, optional)
947 }
948 }
949 TypeRef::Map(_k, v)
951 if config.cast_large_ints_to_f64 && matches!(v.as_ref(), TypeRef::Primitive(p) if needs_f64_cast(p)) =>
952 {
953 if let TypeRef::Primitive(p) = v.as_ref() {
954 let core_ty = core_prim_str(p);
955 if optional {
956 format!("{name}: val.{name}.map(|m| m.into_iter().map(|(k, v)| (k, v as {core_ty})).collect())")
957 } else {
958 format!("{name}: val.{name}.into_iter().map(|(k, v)| (k, v as {core_ty})).collect()")
959 }
960 } else {
961 field_conversion_to_core(name, ty, optional)
962 }
963 }
964 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
967 format!("{name}: Default::default()")
968 }
969 TypeRef::Optional(inner) => match inner.as_ref() {
970 TypeRef::Named(n) if config.from_binding_skip_types.iter().any(|s| s == n) => {
971 format!("{name}: Default::default()")
972 }
973 _ => field_conversion_to_core(name, ty, optional),
974 },
975 _ => field_conversion_to_core(name, ty, optional),
977 }
978}
979
980pub fn apply_core_wrapper_to_core(
983 conversion: &str,
984 name: &str,
985 core_wrapper: &CoreWrapper,
986 vec_inner_core_wrapper: &CoreWrapper,
987 optional: bool,
988) -> String {
989 if *vec_inner_core_wrapper == CoreWrapper::Arc {
991 return conversion
992 .replace(
993 ".map(Into::into).collect()",
994 ".map(|v| std::sync::Arc::new(v.into())).collect()",
995 )
996 .replace(
997 "map(|v| v.into_iter().map(Into::into)",
998 "map(|v| v.into_iter().map(|v| std::sync::Arc::new(v.into()))",
999 );
1000 }
1001
1002 match core_wrapper {
1003 CoreWrapper::None => conversion.to_string(),
1004 CoreWrapper::Cow => {
1005 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1009 if optional {
1010 format!("{name}: {expr}.map(Into::into)")
1011 } else if expr == format!("val.{name}") {
1012 format!("{name}: val.{name}.into()")
1013 } else if expr == "Default::default()" {
1014 conversion.to_string()
1017 } else {
1018 format!("{name}: ({expr}).into()")
1019 }
1020 } else {
1021 conversion.to_string()
1022 }
1023 }
1024 CoreWrapper::Arc => {
1025 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1027 if expr == "Default::default()" {
1028 conversion.to_string()
1031 } else if optional {
1032 format!("{name}: {expr}.map(|v| std::sync::Arc::new(v))")
1033 } else {
1034 format!("{name}: std::sync::Arc::new({expr})")
1035 }
1036 } else {
1037 conversion.to_string()
1038 }
1039 }
1040 CoreWrapper::Bytes => {
1041 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1047 let already_converted_non_opt =
1048 expr == format!("val.{name}.into()") || expr == format!("val.{name}.to_vec().into()");
1049 let already_converted_opt = expr
1050 .strip_prefix(&format!("val.{name}"))
1051 .map(|s| s == ".map(Into::into)" || s == ".map(|v| v.to_vec().into())")
1052 .unwrap_or(false);
1053 if already_converted_non_opt || already_converted_opt {
1054 conversion.to_string()
1056 } else if optional {
1057 format!("{name}: {expr}.map(Into::into)")
1058 } else if expr == format!("val.{name}") {
1059 format!("{name}: val.{name}.into()")
1060 } else if expr == "Default::default()" {
1061 conversion.to_string()
1064 } else {
1065 format!("{name}: ({expr}).into()")
1066 }
1067 } else {
1068 conversion.to_string()
1069 }
1070 }
1071 CoreWrapper::ArcMutex => {
1072 if let Some(expr) = conversion.strip_prefix(&format!("{name}: ")) {
1074 if optional {
1075 format!("{name}: {expr}.map(|v| std::sync::Arc::new(std::sync::Mutex::new(v.into())))")
1076 } else if expr == format!("val.{name}") {
1077 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(val.{name}.into()))")
1078 } else {
1079 format!("{name}: std::sync::Arc::new(std::sync::Mutex::new(({expr}).into()))")
1080 }
1081 } else {
1082 conversion.to_string()
1083 }
1084 }
1085 }
1086}
1087
1088#[cfg(test)]
1089mod tests {
1090 use super::gen_from_binding_to_core;
1091 use alef_core::ir::{CoreWrapper, DefaultValue, FieldDef, TypeDef, TypeRef};
1092
1093 fn type_with_field(field: FieldDef) -> TypeDef {
1094 TypeDef {
1095 name: "ProcessConfig".to_string(),
1096 rust_path: "crate::ProcessConfig".to_string(),
1097 original_rust_path: String::new(),
1098 fields: vec![field],
1099 methods: vec![],
1100 is_opaque: false,
1101 is_clone: true,
1102 is_copy: false,
1103 doc: String::new(),
1104 cfg: None,
1105 is_trait: false,
1106 has_default: true,
1107 has_stripped_cfg_fields: false,
1108 is_return_type: false,
1109 serde_rename_all: None,
1110 has_serde: true,
1111 super_traits: vec![],
1112 }
1113 }
1114
1115 #[test]
1116 fn sanitized_cow_string_field_converts_to_core() {
1117 let field = FieldDef {
1118 name: "language".to_string(),
1119 ty: TypeRef::String,
1120 optional: false,
1121 default: None,
1122 doc: String::new(),
1123 sanitized: true,
1124 is_boxed: false,
1125 type_rust_path: None,
1126 cfg: None,
1127 typed_default: Some(DefaultValue::Empty),
1128 core_wrapper: CoreWrapper::Cow,
1129 vec_inner_core_wrapper: CoreWrapper::None,
1130 newtype_wrapper: None,
1131 serde_rename: None,
1132 serde_flatten: false,
1133 };
1134
1135 let out = gen_from_binding_to_core(&type_with_field(field), "crate");
1136
1137 assert!(out.contains("language: val.language.into()"));
1138 assert!(!out.contains("language: Default::default()"));
1139 }
1140}