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))
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))
39 && is_delegatable_return(&method.return_type)
40}
41
42pub fn is_delegatable_param(ty: &TypeRef, _opaque_types: &AHashSet<String>) -> bool {
44 match ty {
45 TypeRef::Primitive(_)
46 | TypeRef::String
47 | TypeRef::Char
48 | TypeRef::Bytes
49 | TypeRef::Path
50 | TypeRef::Unit
51 | TypeRef::Duration => true,
52 TypeRef::Named(_) => true, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_delegatable_param(inner, _opaque_types),
54 TypeRef::Map(k, v) => is_delegatable_param(k, _opaque_types) && is_delegatable_param(v, _opaque_types),
55 TypeRef::Json => false,
56 }
57}
58
59pub fn is_delegatable_return(ty: &TypeRef) -> bool {
61 match ty {
62 TypeRef::Primitive(_)
63 | TypeRef::String
64 | TypeRef::Char
65 | TypeRef::Bytes
66 | TypeRef::Path
67 | TypeRef::Unit
68 | TypeRef::Duration => true,
69 TypeRef::Named(_) => true, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_delegatable_return(inner),
71 TypeRef::Map(k, v) => is_delegatable_return(k) && is_delegatable_return(v),
72 TypeRef::Json => false,
73 }
74}
75
76pub fn is_delegatable_type(ty: &TypeRef) -> bool {
80 match ty {
81 TypeRef::Primitive(_)
82 | TypeRef::String
83 | TypeRef::Char
84 | TypeRef::Bytes
85 | TypeRef::Path
86 | TypeRef::Unit
87 | TypeRef::Duration => true,
88 TypeRef::Named(_) => false, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_delegatable_type(inner),
90 TypeRef::Map(k, v) => is_delegatable_type(k) && is_delegatable_type(v),
91 TypeRef::Json => false,
92 }
93}
94
95pub fn is_opaque_delegatable_type(ty: &TypeRef) -> bool {
98 match ty {
99 TypeRef::Primitive(_)
100 | TypeRef::String
101 | TypeRef::Char
102 | TypeRef::Bytes
103 | TypeRef::Path
104 | TypeRef::Unit
105 | TypeRef::Duration => true,
106 TypeRef::Named(_) => true, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_opaque_delegatable_type(inner),
108 TypeRef::Map(k, v) => is_opaque_delegatable_type(k) && is_opaque_delegatable_type(v),
109 TypeRef::Json => false,
110 }
111}
112
113pub fn is_simple_type(ty: &TypeRef) -> bool {
115 match ty {
116 TypeRef::Primitive(_)
117 | TypeRef::String
118 | TypeRef::Char
119 | TypeRef::Bytes
120 | TypeRef::Path
121 | TypeRef::Unit
122 | TypeRef::Duration => true,
123 TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_simple_type(inner),
124 TypeRef::Map(k, v) => is_simple_type(k) && is_simple_type(v),
125 TypeRef::Named(_) | TypeRef::Json => false,
126 }
127}
128
129pub fn partition_methods(methods: &[MethodDef]) -> (Vec<&MethodDef>, Vec<&MethodDef>) {
131 let instance: Vec<_> = methods.iter().filter(|m| m.receiver.is_some()).collect();
132 let statics: Vec<_> = methods.iter().filter(|m| m.receiver.is_none()).collect();
133 (instance, statics)
134}
135
136pub fn constructor_parts(fields: &[FieldDef], type_mapper: &dyn Fn(&TypeRef) -> String) -> (String, String, String) {
140 let mut sorted_fields: Vec<&FieldDef> = fields.iter().filter(|f| f.cfg.is_none()).collect();
144 sorted_fields.sort_by_key(|f| f.optional as u8);
145
146 let params: Vec<String> = sorted_fields
147 .iter()
148 .map(|f| {
149 let ty = if f.optional {
150 format!("Option<{}>", type_mapper(&f.ty))
151 } else {
152 type_mapper(&f.ty)
153 };
154 format!("{}: {}", f.name, ty)
155 })
156 .collect();
157
158 let defaults: Vec<String> = sorted_fields
159 .iter()
160 .map(|f| {
161 if f.optional {
162 format!("{}=None", f.name)
163 } else {
164 f.name.clone()
165 }
166 })
167 .collect();
168
169 let assignments: Vec<String> = fields
171 .iter()
172 .filter(|f| f.cfg.is_none())
173 .map(|f| f.name.clone())
174 .collect();
175
176 let single_line = params.join(", ");
178 let param_list = if single_line.len() > 100 {
179 format!("\n {},\n ", params.join(",\n "))
180 } else {
181 single_line
182 };
183
184 (param_list, defaults.join(", "), assignments.join(", "))
185}
186
187pub fn function_params(params: &[ParamDef], type_mapper: &dyn Fn(&TypeRef) -> String) -> String {
189 let mut seen_optional = false;
192 params
193 .iter()
194 .map(|p| {
195 if p.optional {
196 seen_optional = true;
197 }
198 let ty = if p.optional || seen_optional {
199 format!("Option<{}>", type_mapper(&p.ty))
200 } else {
201 type_mapper(&p.ty)
202 };
203 format!("{}: {}", p.name, ty)
204 })
205 .collect::<Vec<_>>()
206 .join(", ")
207}
208
209pub fn function_sig_defaults(params: &[ParamDef]) -> String {
211 let mut seen_optional = false;
214 params
215 .iter()
216 .map(|p| {
217 if p.optional {
218 seen_optional = true;
219 }
220 if p.optional || seen_optional {
221 format!("{}=None", p.name)
222 } else {
223 p.name.clone()
224 }
225 })
226 .collect::<Vec<_>>()
227 .join(", ")
228}
229
230pub fn format_default_value(default: &DefaultValue) -> String {
233 match default {
234 DefaultValue::BoolLiteral(b) => format!("{}", b),
235 DefaultValue::StringLiteral(s) => format!("\"{}\".to_string()", s.escape_default()),
236 DefaultValue::IntLiteral(i) => format!("{}", i),
237 DefaultValue::FloatLiteral(f) => {
238 let s = format!("{}", f);
239 if s.contains('.') || s.contains('e') || s.contains('E') {
241 s
242 } else {
243 format!("{s}.0")
244 }
245 }
246 DefaultValue::EnumVariant(v) => v.clone(),
247 DefaultValue::Empty => "Default::default()".to_string(),
248 DefaultValue::None => "None".to_string(),
249 }
250}
251
252pub fn config_constructor_parts_with_options(
263 fields: &[FieldDef],
264 type_mapper: &dyn Fn(&TypeRef) -> String,
265 option_duration_on_defaults: bool,
266) -> (String, String, String) {
267 config_constructor_parts_inner(fields, type_mapper, option_duration_on_defaults)
268}
269
270pub fn config_constructor_parts(
271 fields: &[FieldDef],
272 type_mapper: &dyn Fn(&TypeRef) -> String,
273) -> (String, String, String) {
274 config_constructor_parts_inner(fields, type_mapper, false)
275}
276
277fn config_constructor_parts_inner(
278 fields: &[FieldDef],
279 type_mapper: &dyn Fn(&TypeRef) -> String,
280 option_duration_on_defaults: bool,
281) -> (String, String, String) {
282 let mut sorted_fields: Vec<&FieldDef> = fields.iter().filter(|f| f.cfg.is_none()).collect();
283 sorted_fields.sort_by_key(|f| f.optional as u8);
284
285 let params: Vec<String> = sorted_fields
286 .iter()
287 .map(|f| {
288 let ty = type_mapper(&f.ty);
289 if matches!(f.ty, TypeRef::Optional(_)) {
294 format!("{}: {}", f.name, ty)
295 } else {
296 format!("{}: Option<{}>", f.name, ty)
297 }
298 })
299 .collect();
300
301 let defaults = sorted_fields
303 .iter()
304 .map(|f| format!("{}=None", f.name))
305 .collect::<Vec<_>>()
306 .join(", ");
307
308 let assignments: Vec<String> = fields
310 .iter()
311 .filter(|f| f.cfg.is_none())
312 .map(|f| {
313 if option_duration_on_defaults && matches!(f.ty, TypeRef::Duration) {
316 return format!("{}: {}", f.name, f.name);
317 }
318 if f.optional || matches!(&f.ty, TypeRef::Optional(_)) {
319 format!("{}: {}", f.name, f.name)
321 } else if let Some(ref typed_default) = f.typed_default {
322 match typed_default {
325 DefaultValue::EnumVariant(_) | DefaultValue::Empty => {
326 format!("{}: {}.unwrap_or_default()", f.name, f.name)
327 }
328 _ => {
329 let default_val = format_default_value(typed_default);
330 match typed_default {
333 DefaultValue::BoolLiteral(_)
334 | DefaultValue::IntLiteral(_)
335 | DefaultValue::FloatLiteral(_) => {
336 format!("{}: {}.unwrap_or({})", f.name, f.name, default_val)
337 }
338 _ => {
339 format!("{}: {}.unwrap_or_else(|| {})", f.name, f.name, default_val)
340 }
341 }
342 }
343 }
344 } else {
345 format!("{}: {}.unwrap_or_default()", f.name, f.name)
348 }
349 })
350 .collect();
351
352 let single_line = params.join(", ");
353 let param_list = if single_line.len() > 100 {
354 format!("\n {},\n ", params.join(",\n "))
355 } else {
356 single_line
357 };
358
359 (param_list, defaults, assignments.join(", "))
360}