1use crate::core::ir::{DefaultValue, FieldDef, MethodDef, ParamDef, PrimitiveType, ReceiverKind, TypeRef};
2use ahash::AHashSet;
3use std::collections::HashMap;
4
5pub fn binding_fields(fields: &[FieldDef]) -> impl Iterator<Item = &FieldDef> {
11 fields.iter().filter(|field| !field.binding_excluded)
12}
13
14pub fn is_promoted_optional(params: &[ParamDef], idx: usize) -> bool {
18 if params[idx].optional {
19 return false; }
21 params[..idx].iter().any(|p| p.optional)
23}
24
25pub fn can_auto_delegate_function(func: &crate::core::ir::FunctionDef, opaque_types: &AHashSet<String>) -> bool {
32 !func.sanitized
33 && func.params.iter().all(|p| {
34 !p.sanitized
35 && is_delegatable_param_with_slices(&p.ty, opaque_types)
36 && !is_named_ref_param(p, opaque_types)
37 })
38 && is_delegatable_return(&func.return_type)
39}
40
41pub fn can_auto_delegate(method: &MethodDef, opaque_types: &AHashSet<String>) -> bool {
47 if matches!(method.receiver, Some(ReceiverKind::RefMut)) && method.trait_source.is_none() {
49 return false;
50 }
51 !method.sanitized
52 && method.params.iter().all(|p| {
53 !p.sanitized
54 && is_delegatable_param_with_slices(&p.ty, opaque_types)
55 && !is_named_ref_param(p, opaque_types)
56 })
57 && is_delegatable_return(&method.return_type)
58}
59
60pub fn is_named_ref_param_pub(p: &crate::core::ir::ParamDef, opaque_types: &AHashSet<String>) -> bool {
66 is_named_ref_param(p, opaque_types)
67}
68
69fn is_named_ref_param(p: &crate::core::ir::ParamDef, opaque_types: &AHashSet<String>) -> bool {
70 if !p.is_ref {
71 return false;
72 }
73 match &p.ty {
74 TypeRef::Named(name) => !opaque_types.contains(name.as_str()),
75 TypeRef::Vec(inner) => match inner.as_ref() {
76 TypeRef::String | TypeRef::Char => true,
77 TypeRef::Named(name) => !opaque_types.contains(name.as_str()),
78 _ => false,
79 },
80 _ => false,
81 }
82}
83
84pub fn is_delegatable_param(ty: &TypeRef, _opaque_types: &AHashSet<String>) -> bool {
90 is_delegatable_param_with_slices(ty, _opaque_types)
91}
92
93fn is_delegatable_param_with_slices(ty: &TypeRef, _opaque_types: &AHashSet<String>) -> bool {
96 match ty {
97 TypeRef::Primitive(_)
98 | TypeRef::String
99 | TypeRef::Char
100 | TypeRef::Bytes
101 | TypeRef::Path
102 | TypeRef::Unit
103 | TypeRef::Duration
104 | TypeRef::Json => true,
105 TypeRef::Named(_) => true, TypeRef::Optional(inner) => is_delegatable_param_with_slices(inner, _opaque_types),
107 TypeRef::Vec(inner) => is_delegatable_param_with_slices(inner, _opaque_types),
110 TypeRef::Map(k, v) => {
111 is_delegatable_param_with_slices(k, _opaque_types) && is_delegatable_param_with_slices(v, _opaque_types)
112 }
113 }
114}
115
116pub fn is_delegatable_return(ty: &TypeRef) -> bool {
121 match ty {
122 TypeRef::Primitive(_)
123 | TypeRef::String
124 | TypeRef::Char
125 | TypeRef::Bytes
126 | TypeRef::Path
127 | TypeRef::Unit
128 | TypeRef::Duration
129 | TypeRef::Json => true,
130 TypeRef::Named(_) => true, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_delegatable_return(inner),
132 TypeRef::Map(k, v) => is_delegatable_return(k) && is_delegatable_return(v),
133 }
134}
135
136pub fn is_delegatable_type(ty: &TypeRef) -> bool {
140 match ty {
141 TypeRef::Primitive(_)
142 | TypeRef::String
143 | TypeRef::Char
144 | TypeRef::Bytes
145 | TypeRef::Path
146 | TypeRef::Unit
147 | TypeRef::Duration => true,
148 TypeRef::Named(_) => false, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_delegatable_type(inner),
150 TypeRef::Map(k, v) => is_delegatable_type(k) && is_delegatable_type(v),
151 TypeRef::Json => false,
152 }
153}
154
155pub fn is_opaque_delegatable_type(ty: &TypeRef) -> bool {
163 match ty {
164 TypeRef::Primitive(_)
165 | TypeRef::String
166 | TypeRef::Char
167 | TypeRef::Bytes
168 | TypeRef::Path
169 | TypeRef::Unit
170 | TypeRef::Duration
171 | TypeRef::Json => true, TypeRef::Named(_) => true, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_opaque_delegatable_type(inner),
174 TypeRef::Map(k, v) => is_opaque_delegatable_type(k) && is_opaque_delegatable_type(v),
175 }
176}
177
178pub fn is_simple_type(ty: &TypeRef) -> bool {
180 match ty {
181 TypeRef::Primitive(_)
182 | TypeRef::String
183 | TypeRef::Char
184 | TypeRef::Bytes
185 | TypeRef::Path
186 | TypeRef::Unit
187 | TypeRef::Duration => true,
188 TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_simple_type(inner),
189 TypeRef::Map(k, v) => is_simple_type(k) && is_simple_type(v),
190 TypeRef::Named(_) | TypeRef::Json => false,
191 }
192}
193
194pub fn partition_methods(methods: &[MethodDef]) -> (Vec<&MethodDef>, Vec<&MethodDef>) {
196 let instance: Vec<_> = methods.iter().filter(|m| m.receiver.is_some()).collect();
197 let statics: Vec<_> = methods.iter().filter(|m| m.receiver.is_none()).collect();
198 (instance, statics)
199}
200
201pub fn constructor_parts(fields: &[FieldDef], type_mapper: &dyn Fn(&TypeRef) -> String) -> (String, String, String) {
205 constructor_parts_with_renames_and_cfg_restore(fields, type_mapper, None, &[])
206}
207
208pub fn constructor_parts_with_renames(
212 fields: &[FieldDef],
213 type_mapper: &dyn Fn(&TypeRef) -> String,
214 field_renames: Option<&HashMap<String, String>>,
215) -> (String, String, String) {
216 constructor_parts_with_renames_and_cfg_restore(fields, type_mapper, field_renames, &[])
217}
218
219pub fn constructor_parts_with_renames_and_cfg_restore(
224 fields: &[FieldDef],
225 type_mapper: &dyn Fn(&TypeRef) -> String,
226 field_renames: Option<&HashMap<String, String>>,
227 never_skip_cfg_field_names: &[String],
228) -> (String, String, String) {
229 let mut sorted_fields: Vec<&FieldDef> = fields
236 .iter()
237 .filter(|f| !f.binding_excluded)
238 .filter(|f| f.cfg.is_none() || never_skip_cfg_field_names.contains(&f.name))
239 .collect();
240 sorted_fields.sort_by_key(|f| (f.optional || f.cfg.is_some()) as u8);
241
242 let params: Vec<String> = sorted_fields
243 .iter()
244 .map(|f| {
245 let is_optional = f.optional || f.cfg.is_some();
246 let ty = if is_optional {
247 match &f.ty {
248 TypeRef::Optional(_) => type_mapper(&f.ty),
249 _ => format!("Option<{}>", type_mapper(&f.ty)),
250 }
251 } else {
252 type_mapper(&f.ty)
253 };
254 format!("{}: {}", f.name, ty)
255 })
256 .collect();
257
258 let defaults: Vec<String> = sorted_fields
259 .iter()
260 .map(|f| {
261 if f.optional || f.cfg.is_some() {
262 format!("{}=None", f.name)
263 } else {
264 f.name.clone()
265 }
266 })
267 .collect();
268
269 let assignments: Vec<String> = fields
274 .iter()
275 .filter(|f| !f.binding_excluded)
276 .map(|f| {
277 let binding_name = field_renames
278 .and_then(|r| r.get(&f.name))
279 .map_or_else(|| f.name.as_str(), |s| s.as_str());
280 if f.cfg.is_some() && !never_skip_cfg_field_names.contains(&f.name) {
281 return format!("{}: Default::default()", binding_name);
282 }
283 if binding_name != f.name {
284 return binding_name.to_string();
285 }
286 f.name.clone()
287 })
288 .collect();
289
290 let single_line = params.join(", ");
292 let param_list = if single_line.len() > 100 {
293 format!("\n {},\n ", params.join(",\n "))
294 } else {
295 single_line
296 };
297
298 (param_list, defaults.join(", "), assignments.join(", "))
299}
300
301pub fn function_params(params: &[ParamDef], type_mapper: &dyn Fn(&TypeRef) -> String) -> String {
303 let mut seen_optional = false;
306 params
307 .iter()
308 .map(|p| {
309 if p.optional {
310 seen_optional = true;
311 }
312 let ty = if p.optional || seen_optional {
313 format!("Option<{}>", type_mapper(&p.ty))
314 } else {
315 type_mapper(&p.ty)
316 };
317 format!("{}: {}", p.name, ty)
318 })
319 .collect::<Vec<_>>()
320 .join(", ")
321}
322
323pub fn function_sig_defaults(params: &[ParamDef]) -> String {
325 let mut seen_optional = false;
331 params
332 .iter()
333 .map(|p| {
334 if p.optional {
335 seen_optional = true;
336 }
337 if p.optional {
338 format!("{}=None", p.name)
339 } else if seen_optional {
340 let default = match &p.ty {
343 TypeRef::Primitive(PrimitiveType::Bool) => "false",
344 TypeRef::Primitive(_) => "0",
345 _ => "None",
346 };
347 format!("{}={}", p.name, default)
348 } else {
349 p.name.clone()
350 }
351 })
352 .collect::<Vec<_>>()
353 .join(", ")
354}
355
356pub fn format_default_value(default: &DefaultValue) -> String {
359 match default {
360 DefaultValue::BoolLiteral(b) => format!("{}", b),
361 DefaultValue::StringLiteral(s) => format!("\"{}\".to_string()", s.escape_default()),
362 DefaultValue::IntLiteral(i) => format!("{}", i),
363 DefaultValue::FloatLiteral(f) => {
364 let s = format!("{}", f);
365 if s.contains('.') || s.contains('e') || s.contains('E') {
367 s
368 } else {
369 format!("{s}.0")
370 }
371 }
372 DefaultValue::EnumVariant(v) => v.clone(),
373 DefaultValue::Empty => "Default::default()".to_string(),
374 DefaultValue::None => "None".to_string(),
375 }
376}
377
378pub fn config_constructor_parts_with_options(
389 fields: &[FieldDef],
390 type_mapper: &dyn Fn(&TypeRef) -> String,
391 option_duration_on_defaults: bool,
392) -> (String, String, String) {
393 config_constructor_parts_with_options_cfg(fields, type_mapper, option_duration_on_defaults, false)
394}
395
396pub fn config_constructor_parts_with_options_cfg(
397 fields: &[FieldDef],
398 type_mapper: &dyn Fn(&TypeRef) -> String,
399 option_duration_on_defaults: bool,
400 optionalize_all_defaults: bool,
401) -> (String, String, String) {
402 config_constructor_parts_inner(
403 fields,
404 type_mapper,
405 option_duration_on_defaults,
406 optionalize_all_defaults,
407 None,
408 &[],
409 )
410}
411
412pub fn config_constructor_parts_with_renames(
414 fields: &[FieldDef],
415 type_mapper: &dyn Fn(&TypeRef) -> String,
416 option_duration_on_defaults: bool,
417 field_renames: Option<&HashMap<String, String>>,
418) -> (String, String, String) {
419 config_constructor_parts_inner(
420 fields,
421 type_mapper,
422 option_duration_on_defaults,
423 false,
424 field_renames,
425 &[],
426 )
427}
428
429pub fn config_constructor_parts_with_renames_and_cfg_restore(
432 fields: &[FieldDef],
433 type_mapper: &dyn Fn(&TypeRef) -> String,
434 option_duration_on_defaults: bool,
435 field_renames: Option<&HashMap<String, String>>,
436 never_skip_cfg_field_names: &[String],
437) -> (String, String, String) {
438 config_constructor_parts_inner(
439 fields,
440 type_mapper,
441 option_duration_on_defaults,
442 false,
443 field_renames,
444 never_skip_cfg_field_names,
445 )
446}
447
448pub fn config_constructor_parts(
449 fields: &[FieldDef],
450 type_mapper: &dyn Fn(&TypeRef) -> String,
451) -> (String, String, String) {
452 config_constructor_parts_inner(fields, type_mapper, false, false, None, &[])
453}
454
455fn config_constructor_parts_inner(
456 fields: &[FieldDef],
457 type_mapper: &dyn Fn(&TypeRef) -> String,
458 option_duration_on_defaults: bool,
459 optionalize_all_defaults: bool,
460 field_renames: Option<&HashMap<String, String>>,
461 never_skip_cfg_field_names: &[String],
462) -> (String, String, String) {
463 let mut sorted_fields: Vec<&FieldDef> = fields
467 .iter()
468 .filter(|f| !f.binding_excluded)
469 .filter(|f| f.cfg.is_none() || never_skip_cfg_field_names.contains(&f.name))
470 .collect();
471 sorted_fields.sort_by_key(|f| f.optional as u8);
472
473 let params: Vec<String> = sorted_fields
474 .iter()
475 .map(|f| {
476 let ty = type_mapper(&f.ty);
477 if matches!(f.ty, TypeRef::Optional(_)) {
482 format!("{}: {}", f.name, ty)
483 } else {
484 format!("{}: Option<{}>", f.name, ty)
485 }
486 })
487 .collect();
488
489 let defaults = sorted_fields
491 .iter()
492 .map(|f| format!("{}=None", f.name))
493 .collect::<Vec<_>>()
494 .join(", ");
495
496 let assignments: Vec<String> = fields
500 .iter()
501 .filter(|f| !f.binding_excluded)
502 .map(|f| {
503 let binding_name = field_renames
504 .and_then(|r| r.get(&f.name))
505 .map_or_else(|| f.name.as_str(), |s| s.as_str());
506 if f.cfg.is_some() {
507 if never_skip_cfg_field_names.contains(&f.name) {
508 if f.optional || matches!(&f.ty, TypeRef::Optional(_)) {
512 return format!("{}: {}", binding_name, f.name);
513 }
514 return format!("{}: {}.unwrap_or_default()", binding_name, f.name);
515 }
516 return format!("{}: Default::default()", binding_name);
517 }
518 if (option_duration_on_defaults && matches!(f.ty, TypeRef::Duration)) || optionalize_all_defaults {
522 return format!("{}: {}", binding_name, f.name);
523 }
524 if f.optional || matches!(&f.ty, TypeRef::Optional(_)) {
525 format!("{}: {}", binding_name, f.name)
527 } else if let Some(ref typed_default) = f.typed_default {
528 match typed_default {
531 DefaultValue::EnumVariant(_) | DefaultValue::Empty => {
532 format!("{}: {}.unwrap_or_default()", binding_name, f.name)
533 }
534 _ => {
535 let default_val = format_default_value(typed_default);
536 match typed_default {
539 DefaultValue::BoolLiteral(_)
540 | DefaultValue::IntLiteral(_)
541 | DefaultValue::FloatLiteral(_) => {
542 format!("{}: {}.unwrap_or({})", binding_name, f.name, default_val)
543 }
544 _ => {
545 format!("{}: {}.unwrap_or_else(|| {})", binding_name, f.name, default_val)
546 }
547 }
548 }
549 }
550 } else {
551 format!("{}: {}.unwrap_or_default()", binding_name, f.name)
554 }
555 })
556 .collect();
557
558 let single_line = params.join(", ");
559 let param_list = if single_line.len() > 100 {
560 format!("\n {},\n ", params.join(",\n "))
561 } else {
562 single_line
563 };
564
565 (param_list, defaults, assignments.join(", "))
566}