1use ahash::AHashSet;
2use alef_core::ir::{DefaultValue, FieldDef, MethodDef, ParamDef, 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 {
29 !method.sanitized
30 && method
31 .params
32 .iter()
33 .all(|p| !p.sanitized && is_delegatable_param(&p.ty, opaque_types))
34 && is_delegatable_return(&method.return_type)
35}
36
37pub fn is_delegatable_param(ty: &TypeRef, _opaque_types: &AHashSet<String>) -> bool {
39 match ty {
40 TypeRef::Primitive(_)
41 | TypeRef::String
42 | TypeRef::Char
43 | TypeRef::Bytes
44 | TypeRef::Path
45 | TypeRef::Unit
46 | TypeRef::Duration => true,
47 TypeRef::Named(_) => true, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_delegatable_param(inner, _opaque_types),
49 TypeRef::Map(k, v) => is_delegatable_param(k, _opaque_types) && is_delegatable_param(v, _opaque_types),
50 TypeRef::Json => false,
51 }
52}
53
54pub fn is_delegatable_return(ty: &TypeRef) -> bool {
56 match ty {
57 TypeRef::Primitive(_)
58 | TypeRef::String
59 | TypeRef::Char
60 | TypeRef::Bytes
61 | TypeRef::Path
62 | TypeRef::Unit
63 | TypeRef::Duration => true,
64 TypeRef::Named(_) => true, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_delegatable_return(inner),
66 TypeRef::Map(k, v) => is_delegatable_return(k) && is_delegatable_return(v),
67 TypeRef::Json => false,
68 }
69}
70
71pub fn is_delegatable_type(ty: &TypeRef) -> bool {
75 match ty {
76 TypeRef::Primitive(_)
77 | TypeRef::String
78 | TypeRef::Char
79 | TypeRef::Bytes
80 | TypeRef::Path
81 | TypeRef::Unit
82 | TypeRef::Duration => true,
83 TypeRef::Named(_) => false, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_delegatable_type(inner),
85 TypeRef::Map(k, v) => is_delegatable_type(k) && is_delegatable_type(v),
86 TypeRef::Json => false,
87 }
88}
89
90pub fn is_opaque_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(_) => true, TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_opaque_delegatable_type(inner),
103 TypeRef::Map(k, v) => is_opaque_delegatable_type(k) && is_opaque_delegatable_type(v),
104 TypeRef::Json => false,
105 }
106}
107
108pub fn is_simple_type(ty: &TypeRef) -> bool {
110 match ty {
111 TypeRef::Primitive(_)
112 | TypeRef::String
113 | TypeRef::Char
114 | TypeRef::Bytes
115 | TypeRef::Path
116 | TypeRef::Unit
117 | TypeRef::Duration => true,
118 TypeRef::Optional(inner) | TypeRef::Vec(inner) => is_simple_type(inner),
119 TypeRef::Map(k, v) => is_simple_type(k) && is_simple_type(v),
120 TypeRef::Named(_) | TypeRef::Json => false,
121 }
122}
123
124pub fn partition_methods(methods: &[MethodDef]) -> (Vec<&MethodDef>, Vec<&MethodDef>) {
126 let instance: Vec<_> = methods.iter().filter(|m| m.receiver.is_some()).collect();
127 let statics: Vec<_> = methods.iter().filter(|m| m.receiver.is_none()).collect();
128 (instance, statics)
129}
130
131pub fn constructor_parts(fields: &[FieldDef], type_mapper: &dyn Fn(&TypeRef) -> String) -> (String, String, String) {
135 let mut sorted_fields: Vec<&FieldDef> = fields.iter().filter(|f| f.cfg.is_none()).collect();
139 sorted_fields.sort_by_key(|f| f.optional as u8);
140
141 let params: Vec<String> = sorted_fields
142 .iter()
143 .map(|f| {
144 let ty = if f.optional {
145 format!("Option<{}>", type_mapper(&f.ty))
146 } else {
147 type_mapper(&f.ty)
148 };
149 format!("{}: {}", f.name, ty)
150 })
151 .collect();
152
153 let defaults: Vec<String> = sorted_fields
154 .iter()
155 .map(|f| {
156 if f.optional {
157 format!("{}=None", f.name)
158 } else {
159 f.name.clone()
160 }
161 })
162 .collect();
163
164 let assignments: Vec<String> = fields
166 .iter()
167 .filter(|f| f.cfg.is_none())
168 .map(|f| f.name.clone())
169 .collect();
170
171 let single_line = params.join(", ");
173 let param_list = if single_line.len() > 100 {
174 format!("\n {},\n ", params.join(",\n "))
175 } else {
176 single_line
177 };
178
179 (param_list, defaults.join(", "), assignments.join(", "))
180}
181
182pub fn function_params(params: &[ParamDef], type_mapper: &dyn Fn(&TypeRef) -> String) -> String {
184 let mut seen_optional = false;
187 params
188 .iter()
189 .map(|p| {
190 if p.optional {
191 seen_optional = true;
192 }
193 let ty = if p.optional || seen_optional {
194 format!("Option<{}>", type_mapper(&p.ty))
195 } else {
196 type_mapper(&p.ty)
197 };
198 format!("{}: {}", p.name, ty)
199 })
200 .collect::<Vec<_>>()
201 .join(", ")
202}
203
204pub fn function_sig_defaults(params: &[ParamDef]) -> String {
206 let mut seen_optional = false;
209 params
210 .iter()
211 .map(|p| {
212 if p.optional {
213 seen_optional = true;
214 }
215 if p.optional || seen_optional {
216 format!("{}=None", p.name)
217 } else {
218 p.name.clone()
219 }
220 })
221 .collect::<Vec<_>>()
222 .join(", ")
223}
224
225pub fn format_default_value(default: &DefaultValue) -> String {
228 match default {
229 DefaultValue::BoolLiteral(b) => format!("{}", b),
230 DefaultValue::StringLiteral(s) => format!("\"{}\".to_string()", s.escape_default()),
231 DefaultValue::IntLiteral(i) => format!("{}", i),
232 DefaultValue::FloatLiteral(f) => format!("{}", f),
233 DefaultValue::EnumVariant(v) => v.clone(),
234 DefaultValue::Empty => "Default::default()".to_string(),
235 DefaultValue::None => "None".to_string(),
236 }
237}
238
239pub fn config_constructor_parts(
246 fields: &[FieldDef],
247 type_mapper: &dyn Fn(&TypeRef) -> String,
248) -> (String, String, String) {
249 let mut sorted_fields: Vec<&FieldDef> = fields.iter().filter(|f| f.cfg.is_none()).collect();
250 sorted_fields.sort_by_key(|f| f.optional as u8);
251
252 let params: Vec<String> = sorted_fields
253 .iter()
254 .map(|f| {
255 let ty = type_mapper(&f.ty);
256 format!("{}: Option<{}>", f.name, ty)
258 })
259 .collect();
260
261 let defaults = sorted_fields
263 .iter()
264 .map(|f| format!("{}=None", f.name))
265 .collect::<Vec<_>>()
266 .join(", ");
267
268 let assignments: Vec<String> = fields
270 .iter()
271 .filter(|f| f.cfg.is_none())
272 .map(|f| {
273 if f.optional || matches!(&f.ty, TypeRef::Optional(_)) {
274 format!("{}: {}", f.name, f.name)
276 } else if let Some(ref typed_default) = f.typed_default {
277 match typed_default {
280 DefaultValue::EnumVariant(_) | DefaultValue::Empty => {
281 format!("{}: {}.unwrap_or_default()", f.name, f.name)
282 }
283 _ => {
284 let default_val = format_default_value(typed_default);
285 match typed_default {
288 DefaultValue::BoolLiteral(_)
289 | DefaultValue::IntLiteral(_)
290 | DefaultValue::FloatLiteral(_) => {
291 format!("{}: {}.unwrap_or({})", f.name, f.name, default_val)
292 }
293 _ => {
294 format!("{}: {}.unwrap_or_else(|| {})", f.name, f.name, default_val)
295 }
296 }
297 }
298 }
299 } else {
300 format!("{}: {}.unwrap_or_default()", f.name, f.name)
303 }
304 })
305 .collect();
306
307 let single_line = params.join(", ");
308 let param_list = if single_line.len() > 100 {
309 format!("\n {},\n ", params.join(",\n "))
310 } else {
311 single_line
312 };
313
314 (param_list, defaults, assignments.join(", "))
315}