1use ahash::AHashSet;
2use alef_core::ir::{DefaultValue, FieldDef, MethodDef, ParamDef, ReceiverKind, TypeRef};
3
4pub fn is_promoted_optional(params: &[ParamDef], idx: usize) -> bool {
8 if params[idx].optional {
9 return false; }
11 params[..idx].iter().any(|p| p.optional)
13}
14
15pub fn can_auto_delegate_function(func: &alef_core::ir::FunctionDef, opaque_types: &AHashSet<String>) -> bool {
19 !func.sanitized
20 && func
21 .params
22 .iter()
23 .all(|p| !p.sanitized && is_delegatable_param(&p.ty, opaque_types) && !is_named_ref_param(p, opaque_types))
24 && is_delegatable_return(&func.return_type)
25}
26
27pub fn can_auto_delegate(method: &MethodDef, opaque_types: &AHashSet<String>) -> bool {
30 if matches!(method.receiver, Some(ReceiverKind::RefMut)) && method.trait_source.is_none() {
32 return false;
33 }
34 !method.sanitized
35 && method
36 .params
37 .iter()
38 .all(|p| !p.sanitized && is_delegatable_param(&p.ty, opaque_types) && !is_named_ref_param(p, opaque_types))
39 && is_delegatable_return(&method.return_type)
40}
41
42fn is_named_ref_param(p: &alef_core::ir::ParamDef, opaque_types: &AHashSet<String>) -> bool {
45 if !p.is_ref {
46 return false;
47 }
48 match &p.ty {
49 TypeRef::Named(name) => !opaque_types.contains(name.as_str()),
50 TypeRef::Vec(inner) => matches!(inner.as_ref(), TypeRef::String | TypeRef::Char),
51 _ => false,
52 }
53}
54
55pub fn is_delegatable_param(ty: &TypeRef, _opaque_types: &AHashSet<String>) -> bool {
57 match ty {
58 TypeRef::Primitive(_)
59 | TypeRef::String
60 | TypeRef::Char
61 | TypeRef::Bytes
62 | TypeRef::Path
63 | TypeRef::Unit
64 | TypeRef::Duration => true,
65 TypeRef::Named(_) => true, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_delegatable_param(inner, _opaque_types),
67 TypeRef::Map(k, v) => is_delegatable_param(k, _opaque_types) && is_delegatable_param(v, _opaque_types),
68 TypeRef::Json => false,
69 }
70}
71
72pub fn is_delegatable_return(ty: &TypeRef) -> bool {
74 match ty {
75 TypeRef::Primitive(_)
76 | TypeRef::String
77 | TypeRef::Char
78 | TypeRef::Bytes
79 | TypeRef::Path
80 | TypeRef::Unit
81 | TypeRef::Duration => true,
82 TypeRef::Named(_) => true, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_delegatable_return(inner),
84 TypeRef::Map(k, v) => is_delegatable_return(k) && is_delegatable_return(v),
85 TypeRef::Json => false,
86 }
87}
88
89pub fn is_delegatable_type(ty: &TypeRef) -> bool {
93 match ty {
94 TypeRef::Primitive(_)
95 | TypeRef::String
96 | TypeRef::Char
97 | TypeRef::Bytes
98 | TypeRef::Path
99 | TypeRef::Unit
100 | TypeRef::Duration => true,
101 TypeRef::Named(_) => false, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_delegatable_type(inner),
103 TypeRef::Map(k, v) => is_delegatable_type(k) && is_delegatable_type(v),
104 TypeRef::Json => false,
105 }
106}
107
108pub fn is_opaque_delegatable_type(ty: &TypeRef) -> bool {
111 match ty {
112 TypeRef::Primitive(_)
113 | TypeRef::String
114 | TypeRef::Char
115 | TypeRef::Bytes
116 | TypeRef::Path
117 | TypeRef::Unit
118 | TypeRef::Duration => true,
119 TypeRef::Named(_) => true, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_opaque_delegatable_type(inner),
121 TypeRef::Map(k, v) => is_opaque_delegatable_type(k) && is_opaque_delegatable_type(v),
122 TypeRef::Json => false,
123 }
124}
125
126pub fn is_simple_type(ty: &TypeRef) -> bool {
128 match ty {
129 TypeRef::Primitive(_)
130 | TypeRef::String
131 | TypeRef::Char
132 | TypeRef::Bytes
133 | TypeRef::Path
134 | TypeRef::Unit
135 | TypeRef::Duration => true,
136 TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_simple_type(inner),
137 TypeRef::Map(k, v) => is_simple_type(k) && is_simple_type(v),
138 TypeRef::Named(_) | TypeRef::Json => false,
139 }
140}
141
142pub fn partition_methods(methods: &[MethodDef]) -> (Vec<&MethodDef>, Vec<&MethodDef>) {
144 let instance: Vec<_> = methods.iter().filter(|m| m.receiver.is_some()).collect();
145 let statics: Vec<_> = methods.iter().filter(|m| m.receiver.is_none()).collect();
146 (instance, statics)
147}
148
149pub fn constructor_parts(fields: &[FieldDef], type_mapper: &dyn Fn(&TypeRef) -> String) -> (String, String, String) {
153 let mut sorted_fields: Vec<&FieldDef> = fields.iter().filter(|f| f.cfg.is_none()).collect();
157 sorted_fields.sort_by_key(|f| f.optional as u8);
158
159 let params: Vec<String> = sorted_fields
160 .iter()
161 .map(|f| {
162 let ty = if f.optional {
163 format!("Option<{}>", type_mapper(&f.ty))
164 } else {
165 type_mapper(&f.ty)
166 };
167 format!("{}: {}", f.name, ty)
168 })
169 .collect();
170
171 let defaults: Vec<String> = sorted_fields
172 .iter()
173 .map(|f| {
174 if f.optional {
175 format!("{}=None", f.name)
176 } else {
177 f.name.clone()
178 }
179 })
180 .collect();
181
182 let assignments: Vec<String> = fields
184 .iter()
185 .filter(|f| f.cfg.is_none())
186 .map(|f| f.name.clone())
187 .collect();
188
189 let single_line = params.join(", ");
191 let param_list = if single_line.len() > 100 {
192 format!("\n {},\n ", params.join(",\n "))
193 } else {
194 single_line
195 };
196
197 (param_list, defaults.join(", "), assignments.join(", "))
198}
199
200pub fn function_params(params: &[ParamDef], type_mapper: &dyn Fn(&TypeRef) -> String) -> String {
202 let mut seen_optional = false;
205 params
206 .iter()
207 .map(|p| {
208 if p.optional {
209 seen_optional = true;
210 }
211 let ty = if p.optional || seen_optional {
212 format!("Option<{}>", type_mapper(&p.ty))
213 } else {
214 type_mapper(&p.ty)
215 };
216 format!("{}: {}", p.name, ty)
217 })
218 .collect::<Vec<_>>()
219 .join(", ")
220}
221
222pub fn function_sig_defaults(params: &[ParamDef]) -> String {
224 let mut seen_optional = false;
227 params
228 .iter()
229 .map(|p| {
230 if p.optional {
231 seen_optional = true;
232 }
233 if p.optional || seen_optional {
234 format!("{}=None", p.name)
235 } else {
236 p.name.clone()
237 }
238 })
239 .collect::<Vec<_>>()
240 .join(", ")
241}
242
243pub fn format_default_value(default: &DefaultValue) -> String {
246 match default {
247 DefaultValue::BoolLiteral(b) => format!("{}", b),
248 DefaultValue::StringLiteral(s) => format!("\"{}\".to_string()", s.escape_default()),
249 DefaultValue::IntLiteral(i) => format!("{}", i),
250 DefaultValue::FloatLiteral(f) => {
251 let s = format!("{}", f);
252 if s.contains('.') || s.contains('e') || s.contains('E') {
254 s
255 } else {
256 format!("{s}.0")
257 }
258 }
259 DefaultValue::EnumVariant(v) => v.clone(),
260 DefaultValue::Empty => "Default::default()".to_string(),
261 DefaultValue::None => "None".to_string(),
262 }
263}
264
265pub fn config_constructor_parts_with_options(
276 fields: &[FieldDef],
277 type_mapper: &dyn Fn(&TypeRef) -> String,
278 option_duration_on_defaults: bool,
279) -> (String, String, String) {
280 config_constructor_parts_inner(fields, type_mapper, option_duration_on_defaults)
281}
282
283pub fn config_constructor_parts(
284 fields: &[FieldDef],
285 type_mapper: &dyn Fn(&TypeRef) -> String,
286) -> (String, String, String) {
287 config_constructor_parts_inner(fields, type_mapper, false)
288}
289
290fn config_constructor_parts_inner(
291 fields: &[FieldDef],
292 type_mapper: &dyn Fn(&TypeRef) -> String,
293 option_duration_on_defaults: bool,
294) -> (String, String, String) {
295 let mut sorted_fields: Vec<&FieldDef> = fields.iter().filter(|f| f.cfg.is_none()).collect();
296 sorted_fields.sort_by_key(|f| f.optional as u8);
297
298 let params: Vec<String> = sorted_fields
299 .iter()
300 .map(|f| {
301 let ty = type_mapper(&f.ty);
302 if matches!(f.ty, TypeRef::Optional(_)) {
307 format!("{}: {}", f.name, ty)
308 } else {
309 format!("{}: Option<{}>", f.name, ty)
310 }
311 })
312 .collect();
313
314 let defaults = sorted_fields
316 .iter()
317 .map(|f| format!("{}=None", f.name))
318 .collect::<Vec<_>>()
319 .join(", ");
320
321 let assignments: Vec<String> = fields
323 .iter()
324 .filter(|f| f.cfg.is_none())
325 .map(|f| {
326 if option_duration_on_defaults && matches!(f.ty, TypeRef::Duration) {
329 return format!("{}: {}", f.name, f.name);
330 }
331 if f.optional || matches!(&f.ty, TypeRef::Optional(_)) {
332 format!("{}: {}", f.name, f.name)
334 } else if let Some(ref typed_default) = f.typed_default {
335 match typed_default {
338 DefaultValue::EnumVariant(_) | DefaultValue::Empty => {
339 format!("{}: {}.unwrap_or_default()", f.name, f.name)
340 }
341 _ => {
342 let default_val = format_default_value(typed_default);
343 match typed_default {
346 DefaultValue::BoolLiteral(_)
347 | DefaultValue::IntLiteral(_)
348 | DefaultValue::FloatLiteral(_) => {
349 format!("{}: {}.unwrap_or({})", f.name, f.name, default_val)
350 }
351 _ => {
352 format!("{}: {}.unwrap_or_else(|| {})", f.name, f.name, default_val)
353 }
354 }
355 }
356 }
357 } else {
358 format!("{}: {}.unwrap_or_default()", f.name, f.name)
361 }
362 })
363 .collect();
364
365 let single_line = params.join(", ");
366 let param_list = if single_line.len() > 100 {
367 format!("\n {},\n ", params.join(",\n "))
368 } else {
369 single_line
370 };
371
372 (param_list, defaults, assignments.join(", "))
373}