1use crate::generator::{is_sync_handler_type, Arg, ArgProcessing, CHandler, CWrapper, Method, ReturnType};
8use crate::snake_to_pascal_case;
9use proc_macro2::TokenStream;
10use quote::{format_ident, quote};
11use std::collections::BTreeMap;
12use syn::{parse_str, Type};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum ArgRole {
21 SelfPointer,
23 WrapperPointer,
25 HandlerSync,
27 HandlerRetainedBorrowed,
30 HandlerRetainedOwned,
33 Absorbed,
35 Plain,
37}
38
39pub struct ClassifiedArg {
41 pub kind: ArgRole,
42 pub signature: Option<TokenStream>,
44 pub call: Option<TokenStream>,
46 pub generic: Option<TokenStream>,
48 pub registration: Option<TokenStream>,
50 pub prelude: Option<TokenStream>,
53 pub once_signature: Option<TokenStream>,
55 pub once_call: Option<TokenStream>,
56 pub once_generic: Option<TokenStream>,
57}
58
59pub struct ClassifiedMethodArgs {
60 pub uses_self: bool,
61 pub args: Vec<ClassifiedArg>,
62 pub owned_retained: Option<Arg>,
64 pub once_capable: bool,
66}
67
68impl ClassifiedMethodArgs {
69 pub fn signatures(&self) -> Vec<TokenStream> {
70 self.args.iter().filter_map(|a| a.signature.clone()).collect()
71 }
72
73 pub fn calls(&self) -> Vec<TokenStream> {
74 self.args.iter().filter_map(|a| a.call.clone()).collect()
75 }
76
77 pub fn generics(&self) -> Vec<TokenStream> {
78 self.args.iter().filter_map(|a| a.generic.clone()).collect()
79 }
80
81 pub fn registrations(&self) -> Vec<TokenStream> {
82 self.args.iter().filter_map(|a| a.registration.clone()).collect()
83 }
84
85 pub fn preludes(&self) -> Vec<TokenStream> {
87 self.args.iter().filter_map(|a| a.prelude.clone()).collect()
88 }
89
90 pub fn once_signatures(&self) -> Vec<TokenStream> {
91 self.args
92 .iter()
93 .filter_map(|a| a.once_signature.clone().or_else(|| a.signature.clone()))
94 .collect()
95 }
96
97 pub fn once_calls(&self) -> Vec<TokenStream> {
98 self.args
99 .iter()
100 .filter_map(|a| a.once_call.clone().or_else(|| a.call.clone()))
101 .collect()
102 }
103
104 pub fn once_generics(&self) -> Vec<TokenStream> {
105 self.args
106 .iter()
107 .filter_map(|a| a.once_generic.clone().or_else(|| a.generic.clone()))
108 .collect()
109 }
110}
111
112pub fn classify_method_args(
115 method: &Method,
116 own_type_name: &str,
117 wrappers: &BTreeMap<String, CWrapper>,
118 closure_handlers: &[CHandler],
119) -> ClassifiedMethodArgs {
120 let uses_self_precheck = method
121 .arguments
122 .iter()
123 .any(|arg| arg.is_single_mut_pointer() && arg.c_type.ends_with(own_type_name));
124 let handler_value_args: Vec<&Arg> = method
125 .arguments
126 .iter()
127 .filter(|a| matches!(a.processing, ArgProcessing::Handler(_)) && !a.is_mut_pointer())
128 .collect();
129 let has_mut_primitive = method.arguments.iter().any(|a| a.is_mut_pointer() && a.is_primitive());
130 let owned_retained: Option<Arg> = if uses_self_precheck
131 && !has_mut_primitive
132 && method.return_type.is_c_raw_int()
133 && handler_value_args.len() == 1
134 {
135 let a = handler_value_args[0];
136 match &a.processing {
137 ArgProcessing::Handler(hc) if !is_sync_handler_type(&hc[0].c_type) => Some(a.clone()),
138 _ => None,
139 }
140 } else {
141 None
142 };
143 let once_capable = !handler_value_args.is_empty()
144 && handler_value_args.iter().all(|arg| match &arg.processing {
145 ArgProcessing::Handler(hc) => is_sync_handler_type(&hc[0].c_type),
146 _ => false,
147 });
148
149 let mut uses_self = false;
150 let args = method
151 .arguments
152 .iter()
153 .map(|arg| {
154 classify_arg(
155 arg,
156 own_type_name,
157 wrappers,
158 closure_handlers,
159 &owned_retained,
160 &mut uses_self,
161 )
162 })
163 .collect();
164
165 ClassifiedMethodArgs {
166 uses_self,
167 args,
168 owned_retained,
169 once_capable,
170 }
171}
172
173fn classify_arg(
174 arg: &Arg,
175 own_type_name: &str,
176 wrappers: &BTreeMap<String, CWrapper>,
177 closure_handlers: &[CHandler],
178 owned_retained: &Option<Arg>,
179 uses_self: &mut bool,
180) -> ClassifiedArg {
181 let none = ClassifiedArg {
182 kind: ArgRole::Absorbed,
183 signature: None,
184 call: None,
185 generic: None,
186 registration: None,
187 prelude: None,
188 once_signature: None,
189 once_call: None,
190 once_generic: None,
191 };
192
193 let pointee = if arg.is_single_mut_pointer() {
195 arg.c_type.split(' ').last().unwrap_or("notfound")
196 } else {
197 "notfound"
198 };
199 if let Some(matching_wrapper) = wrappers.get(pointee) {
200 let name = arg.as_ident();
201 if arg.c_type.ends_with(own_type_name) && matching_wrapper.type_name == own_type_name {
202 *uses_self = true;
203 return ClassifiedArg {
204 kind: ArgRole::SelfPointer,
205 call: Some(quote! { self.get_inner() }),
206 ..none
207 };
208 }
209 let arg_type = ReturnType::new(arg.clone(), wrappers.clone()).get_new_return_type(false, true);
210 return ClassifiedArg {
211 kind: ArgRole::WrapperPointer,
212 signature: if arg_type.is_empty() {
213 None
214 } else {
215 Some(quote! { #name: #arg_type })
216 },
217 call: Some(quote! { #name.get_inner() }),
218 ..none
219 };
220 }
221
222 if let ArgProcessing::Handler(handler_client) = &arg.processing {
224 if !arg.is_mut_pointer() {
225 return classify_handler_arg(arg, handler_client, wrappers, closure_handlers, owned_retained, none);
226 }
227 return none;
229 }
230
231 let name = arg.as_ident();
234 let rt = ReturnType::new(arg.clone(), wrappers.clone());
235 let arg_type = rt.get_new_return_type(false, true);
236 let call = rt.handle_rs_to_c_return(quote! { #name }, false);
237 ClassifiedArg {
238 kind: ArgRole::Plain,
239 signature: if arg_type.is_empty() {
240 None
241 } else {
242 Some(quote! { #name: #arg_type })
243 },
244 call: if call.is_empty() { None } else { Some(quote! { #call }) },
245 generic: rt.method_generics_for_where(false),
246 ..none
247 }
248}
249
250fn classify_handler_arg(
251 arg: &Arg,
252 handler_client: &[Arg],
253 wrappers: &BTreeMap<String, CWrapper>,
254 closure_handlers: &[CHandler],
255 owned_retained: &Option<Arg>,
256 none: ClassifiedArg,
257) -> ClassifiedArg {
258 let handler = handler_client.first().unwrap();
259 let name = arg.as_ident();
260 let raw_name = format_ident!("{}_raw", arg.name);
261 let shim = format_ident!("{}_callback", handler.c_type);
262 let once_shim = format_ident!("{}_callback_for_once_closure", handler.c_type);
263 let handler_type = handler.as_type();
264 let new_type =
265 parse_str::<Type>(&format!("{}HandlerImpl", snake_to_pascal_case(&arg.c_type))).expect("Invalid class name");
266 let sync = is_sync_handler_type(&handler.c_type);
267 let is_owned = owned_retained.as_ref().map(|o| o.name == arg.name).unwrap_or(false);
268 let rt = ReturnType::new(arg.clone(), wrappers.clone());
269
270 if is_owned {
271 return ClassifiedArg {
273 kind: ArgRole::HandlerRetainedOwned,
274 signature: Some(quote! { #name: Option<#new_type> }),
275 call: Some(quote! {
276 {
277 let callback: #handler_type = if #raw_name.is_null() {
278 None
279 } else {
280 Some(#shim::<#new_type>)
281 };
282 callback
283 },
284 #raw_name
285 }),
286 generic: rt.method_generics_for_where(false),
287 registration: Some(quote! {
288 if let Some(__handler) = &#name {
289 if let Some(__inner) = self.inner.as_owned() {
290 __inner.add_dependency(__handler.clone());
291 }
292 }
293 }),
294 ..none
295 };
296 }
297
298 let borrow_call = quote! {
300 {
301 let callback: #handler_type = if #name.is_none() {
302 None
303 } else {
304 Some(#shim::<#new_type>)
305 };
306 callback
307 },
308 #name.map(|m| m.as_raw()).unwrap_or_else(|| std::ptr::null_mut())
309 };
310 if sync {
311 let fn_mut_sig = closure_handlers
314 .iter()
315 .find(|c| c.type_name == handler.c_type)
316 .map(|c| c.fn_mut_signature.clone())
317 .unwrap_or_else(|| quote! { FnMut() -> () });
318 ClassifiedArg {
319 kind: ArgRole::HandlerSync,
320 signature: Some(quote! { #name: Option<&Handler<#new_type>> }),
321 call: Some(borrow_call),
322 generic: rt.method_generics_for_where(false),
323 once_signature: Some(quote! { mut #name: #new_type }),
324 once_call: Some(quote! {
325 Some(#once_shim::<#new_type>),
326 &mut #name as *mut _ as *mut std::os::raw::c_void
327 }),
328 once_generic: Some(quote! { #new_type: #fn_mut_sig }),
329 ..none
330 }
331 } else {
332 ClassifiedArg {
333 kind: ArgRole::HandlerRetainedBorrowed,
334 signature: Some(quote! { #name: Option<&Handler<#new_type>> }),
335 call: Some(borrow_call),
336 generic: rt.method_generics_for_where(false),
337 registration: Some(quote! {
338 if let Some(__handler) = #name {
339 if let Some(__inner) = self.inner.as_owned() {
340 __inner.add_dependency(__handler.clone());
341 }
342 }
343 }),
344 ..none
345 }
346 }
347}
348
349#[cfg(test)]
350mod tests {
351 use super::*;
352
353 fn arg(name: &str, c_type: &str, processing: ArgProcessing) -> Arg {
354 Arg {
355 name: name.to_string(),
356 c_type: c_type.to_string(),
357 processing,
358 }
359 }
360
361 fn handler_pair(name: &str, c_type: &str) -> Arg {
362 let cb = arg(name, c_type, ArgProcessing::Default);
363 let clientd = arg("clientd", "* mut :: std :: os :: raw :: c_void", ArgProcessing::Default);
364 arg(name, c_type, ArgProcessing::Handler(vec![cb, clientd]))
365 }
366
367 fn method(name: &str, ret: &str, args: Vec<Arg>) -> Method {
368 Method {
369 fn_name: format!("aeron_x_{name}"),
370 struct_method_name: name.to_string(),
371 return_type: arg("", ret, ArgProcessing::Default),
372 arguments: args,
373 docs: Default::default(),
374 }
375 }
376
377 #[test]
378 fn retained_handler_on_int_setter_is_owned() {
379 let m = method(
380 "set_error_handler",
381 ":: std :: os :: raw :: c_int",
382 vec![
383 arg("ctx", "* mut aeron_context_t", ArgProcessing::Default),
384 handler_pair("handler", "aeron_error_handler_t"),
385 ],
386 );
387 let mut wrappers = BTreeMap::new();
388 wrappers.insert(
389 "aeron_context_t".to_string(),
390 CWrapper {
391 type_name: "aeron_context_t".to_string(),
392 class_name: "AeronContext".to_string(),
393 ..Default::default()
394 },
395 );
396 let classified = classify_method_args(&m, "aeron_context_t", &wrappers, &[]);
397 assert!(classified.uses_self);
398 assert!(
399 classified.owned_retained.is_some(),
400 "error handler must be an owned setter"
401 );
402 assert!(
403 !classified.once_capable,
404 "retained callbacks must not get a _fn variant"
405 );
406 assert_eq!(classified.args[1].kind, ArgRole::HandlerRetainedOwned);
407 assert!(classified.args[1].registration.is_some());
408 }
409
410 #[test]
411 fn sync_handler_is_once_capable_and_not_registered() {
412 let m = method(
413 "poll",
414 ":: std :: os :: raw :: c_int",
415 vec![
416 arg("subscription", "* mut aeron_subscription_t", ArgProcessing::Default),
417 handler_pair("handler", "aeron_fragment_handler_t"),
418 ],
419 );
420 let mut wrappers = BTreeMap::new();
421 wrappers.insert(
422 "aeron_subscription_t".to_string(),
423 CWrapper {
424 type_name: "aeron_subscription_t".to_string(),
425 class_name: "AeronSubscription".to_string(),
426 ..Default::default()
427 },
428 );
429 let classified = classify_method_args(&m, "aeron_subscription_t", &wrappers, &[]);
430 assert!(classified.once_capable, "sync callbacks get a _fn variant");
431 assert!(classified.owned_retained.is_none());
432 assert_eq!(classified.args[1].kind, ArgRole::HandlerSync);
433 assert!(
434 classified.args[1].registration.is_none(),
435 "sync handlers are never retained"
436 );
437 assert!(classified.args[1].once_call.is_some());
438 }
439
440 #[test]
441 fn clientd_and_self_absorb_correctly() {
442 let m = method(
443 "poll",
444 ":: std :: os :: raw :: c_int",
445 vec![arg(
446 "subscription",
447 "* mut aeron_subscription_t",
448 ArgProcessing::Default,
449 )],
450 );
451 let mut wrappers = BTreeMap::new();
452 wrappers.insert(
453 "aeron_subscription_t".to_string(),
454 CWrapper {
455 type_name: "aeron_subscription_t".to_string(),
456 class_name: "AeronSubscription".to_string(),
457 ..Default::default()
458 },
459 );
460 let classified = classify_method_args(&m, "aeron_subscription_t", &wrappers, &[]);
461 assert_eq!(classified.args[0].kind, ArgRole::SelfPointer);
462 assert!(classified.args[0].signature.is_none());
463 assert_eq!(classified.signatures().len(), 0);
464 assert_eq!(classified.calls().len(), 1);
465 }
466}