1use crate::get_possible_wrappers;
2#[allow(unused_imports)]
3use crate::snake_to_pascal_case;
4use itertools::Itertools;
5use proc_macro2::{Ident, TokenStream};
6use quote::{format_ident, quote, ToTokens};
7use std::collections::{BTreeMap, BTreeSet, HashMap};
8use std::ops::Deref;
9use std::str::FromStr;
10use syn::{parse_str, ImplItem, Item, Type};
11
12pub const COMMON_CODE: &str = include_str!("common.rs");
13pub const CLIENT_BINDINGS: &str = include_str!("../bindings/client.rs");
14pub const ARCHIVE_BINDINGS: &str = include_str!("../bindings/archive.rs");
15pub const MEDIA_DRIVER_BINDINGS: &str = include_str!("../bindings/media-driver.rs");
16
17#[derive(Debug, Clone, Default)]
18pub struct CBinding {
19 pub wrappers: BTreeMap<String, CWrapper>,
20 pub methods: Vec<Method>,
21 pub handlers: Vec<CHandler>,
22}
23
24#[derive(Debug, Clone, Eq, PartialEq)]
25pub struct Method {
26 pub fn_name: String,
27 pub struct_method_name: String,
28 pub return_type: Arg,
29 pub arguments: Vec<Arg>,
30 pub docs: BTreeSet<String>,
31}
32
33#[derive(Debug, Clone, Eq, PartialEq)]
34pub enum ArgProcessing {
35 Handler(Vec<Arg>),
36 StringWithLength(Vec<Arg>),
37 ByteArrayWithLength(Vec<Arg>),
38 Default,
39}
40
41#[derive(Debug, Clone, Eq, PartialEq)]
42pub struct Arg {
43 pub name: String,
44 pub c_type: String,
45 pub processing: ArgProcessing,
46}
47
48impl Arg {
49 pub fn is_primitive(&self) -> bool {
50 static PRIMITIVE_TYPES: &[&str] = &[
51 "i64", "u64", "f32", "f64", "i32", "i16", "u32", "u16", "bool", "usize", "isize",
52 ];
53 PRIMITIVE_TYPES.iter().any(|&f| self.c_type.ends_with(f))
54 }
55}
56
57impl Arg {
58 const C_INT_RETURN_TYPE_STR: &'static str = ":: std :: os :: raw :: c_int";
59 const C_CHAR_STR: &'static str = "* const :: std :: os :: raw :: c_char";
60 const C_MUT_CHAR_STR: &'static str = "* mut :: std :: os :: raw :: c_char";
61 const C_BYTE_ARRAY: &'static str = "* const u8";
62 const C_BYTE_MUT_ARRAY: &'static str = "* mut u8";
63 const STAR_MUT: &'static str = "* mut";
64 const DOUBLE_STAR_MUT: &'static str = "* mut * mut";
65 const C_VOID: &'static str = "* mut :: std :: os :: raw :: c_void";
66
67 pub fn is_any_pointer(&self) -> bool {
68 self.c_type.starts_with("* const") || self.c_type.starts_with("* mut")
69 }
70
71 pub fn is_c_string(&self) -> bool {
72 self.c_type == Self::C_CHAR_STR
73 }
74
75 pub fn is_c_string_any(&self) -> bool {
76 self.is_c_string() || self.is_mut_c_string()
77 }
78
79 pub fn is_mut_c_string(&self) -> bool {
80 self.c_type == Self::C_MUT_CHAR_STR
81 }
82
83 pub fn is_usize(&self) -> bool {
84 self.c_type == "usize"
85 }
86
87 pub fn is_byte_array(&self) -> bool {
88 self.c_type == Self::C_BYTE_ARRAY || self.c_type == Self::C_BYTE_MUT_ARRAY
89 }
90
91 pub fn is_mut_byte_array(&self) -> bool {
92 self.c_type == Self::C_BYTE_MUT_ARRAY
93 }
94
95 pub fn is_c_raw_int(&self) -> bool {
96 self.c_type == Self::C_INT_RETURN_TYPE_STR
97 }
98
99 pub fn is_mut_pointer(&self) -> bool {
100 self.c_type.starts_with(Self::STAR_MUT)
101 }
102
103 pub fn is_double_mut_pointer(&self) -> bool {
104 self.c_type.starts_with(Self::DOUBLE_STAR_MUT)
105 }
106
107 pub fn is_single_mut_pointer(&self) -> bool {
108 self.is_mut_pointer() && !self.is_double_mut_pointer()
109 }
110
111 pub fn is_c_void(&self) -> bool {
112 self.c_type == Self::C_VOID
113 }
114}
115
116impl Deref for Arg {
117 type Target = str;
118
119 fn deref(&self) -> &Self::Target {
120 &self.c_type
121 }
122}
123
124impl Arg {
125 pub fn as_ident(&self) -> Ident {
126 Ident::new(&self.name, proc_macro2::Span::call_site())
127 }
128
129 pub fn as_type(&self) -> Type {
130 parse_str(&self.c_type).expect("Invalid argument type")
131 }
132}
133
134#[derive(Debug, Clone)]
135pub struct CHandler {
136 pub type_name: String,
137 pub args: Vec<Arg>,
138 pub return_type: Arg,
139 pub docs: BTreeSet<String>,
140 pub fn_mut_signature: TokenStream,
141 pub closure_type_name: TokenStream,
142}
143
144#[derive(Debug, Clone)]
145pub struct ReturnType {
146 original: Arg,
147 wrappers: BTreeMap<String, CWrapper>,
148}
149
150impl ReturnType {
151 pub fn new(original_c_type: Arg, wrappers: BTreeMap<String, CWrapper>) -> Self {
152 ReturnType {
153 original: original_c_type,
154 wrappers,
155 }
156 }
157
158 pub fn get_new_return_type(&self, convert_errors: bool, use_ref_for_cwrapper: bool) -> TokenStream {
159 if let ArgProcessing::Handler(_) = self.original.processing {
160 if self.original.name.len() > 0 {
161 if !self.original.is_mut_pointer() {
162 let new_type =
163 parse_str::<Type>(&format!("{}HandlerImpl", snake_to_pascal_case(&self.original.c_type)))
164 .expect("Invalid class name in wrapper");
165 return quote! { Option<&Handler<#new_type>> };
166 } else {
167 return quote! {};
168 }
169 }
170 } else if let ArgProcessing::StringWithLength(_) = self.original.processing {
171 if self.original.name.len() > 0 {
172 if self.original.is_c_string() {
173 return quote! { &str };
174 } else if self.original.is_mut_c_string() {
175 } else {
177 return quote! {};
178 }
179 }
180 } else if let ArgProcessing::ByteArrayWithLength(_) = self.original.processing {
181 if self.original.name.len() > 0 {
182 if self.original.is_byte_array() {
183 if self.original.is_mut_byte_array() {
184 return quote! { &mut [u8] };
185 } else {
186 return quote! { &[u8] };
187 }
188 } else {
189 return quote! {};
190 }
191 }
192 }
193
194 if self.original.is_single_mut_pointer() {
195 let type_name = self.original.split(" ").last().unwrap();
196 if let Some(wrapper) = self.wrappers.get(type_name) {
197 let new_type = parse_str::<Type>(&wrapper.class_name).expect("Invalid class name in wrapper");
198 if use_ref_for_cwrapper {
199 return quote! { &#new_type };
200 } else {
201 return quote! { #new_type };
202 }
203 }
204 }
205 if let Some(wrapper) = self.wrappers.get(&self.original.c_type) {
206 let new_type = parse_str::<Type>(&wrapper.class_name).expect("Invalid class name in wrapper");
207 return quote! { #new_type };
208 }
209 if convert_errors && self.original.is_c_raw_int() {
210 return quote! { Result<i32, AeronCError> };
211 }
212 if self.original.is_c_string() {
213 if !convert_errors && use_ref_for_cwrapper {
215 return quote! { &std::ffi::CStr };
216 } else {
217 return quote! { &str };
218 }
219 }
220 let return_type: Type = parse_str(&self.original).expect("Invalid return type");
221 if self.original.is_single_mut_pointer() && self.original.is_primitive() {
222 let mut_type: Type =
223 parse_str(&return_type.to_token_stream().to_string().replace("* mut ", "&mut ")).unwrap();
224 return quote! { #mut_type };
225 }
226 quote! { #return_type }
227 }
228
229 pub fn handle_c_to_rs_return(&self, result: TokenStream, convert_errors: bool, use_self: bool) -> TokenStream {
230 if let ArgProcessing::StringWithLength(_) = &self.original.processing {
231 if !self.original.is_c_string_any() {
232 return quote! {};
233 }
234 }
235 if let ArgProcessing::ByteArrayWithLength(args) = &self.original.processing {
236 if !self.original.is_byte_array() {
237 return quote! {};
238 } else {
239 let star_const = &args[0].as_ident();
240 let length = &args[1].as_ident();
241 let me = if use_self {
242 quote! {self.}
243 } else {
244 quote! {}
245 };
246 if self.original.is_mut_byte_array() {
247 return quote! {
248 unsafe { if #me #star_const.is_null() { &mut [] as &mut [_] } else {std::slice::from_raw_parts_mut(#me #star_const, #me #length.try_into().unwrap()) } }
249 };
250 } else {
251 return quote! {
252 if #me #star_const.is_null() { &[] as &[_] } else { std::slice::from_raw_parts(#me #star_const, #me #length.try_into().unwrap()) }
253 };
254 }
255 }
256 }
257
258 if convert_errors && self.original.is_c_raw_int() {
259 quote! {
260 if result < 0 {
261 return Err(AeronCError::from_code(result));
262 } else {
263 return Ok(result)
264 }
265 }
266 } else if self.original.is_c_string() {
267 if let ArgProcessing::StringWithLength(args) = &self.original.processing {
268 let length = &args[1].as_ident();
269 return quote! { if #result.is_null() { ""} else { std::str::from_utf8_unchecked(std::slice::from_raw_parts(#result as *const u8, #length.try_into().unwrap()))}};
270 } else {
271 return quote! { if #result.is_null() { ""} else { unsafe { std::ffi::CStr::from_ptr(#result).to_str().unwrap_or("") } } };
272 }
273 } else if self.original.is_single_mut_pointer() && self.original.is_primitive() {
274 return quote! {
275 unsafe { &mut *#result }
276 };
277 } else {
278 quote! { #result.into() }
279 }
280 }
281
282 pub fn method_generics_for_where(&self) -> Option<TokenStream> {
283 if let ArgProcessing::Handler(handler_client) = &self.original.processing {
284 if !self.original.is_mut_pointer() {
285 let handler = handler_client.get(0).unwrap();
286 let new_type = parse_str::<Type>(&format!("{}HandlerImpl", snake_to_pascal_case(&handler.c_type)))
287 .expect("Invalid class name in wrapper");
288 let new_handler = parse_str::<Type>(&format!("{}Callback", snake_to_pascal_case(&handler.c_type)))
289 .expect("Invalid class name in wrapper");
290 return Some(quote! {
291 #new_type: #new_handler
292 });
293 }
294 }
295 None
296 }
297
298 pub fn method_generics_for_method(&self) -> Option<TokenStream> {
299 if let ArgProcessing::Handler(handler_client) = &self.original.processing {
300 if !self.original.is_mut_pointer() {
301 let handler = handler_client.get(0).unwrap();
302 let new_type = parse_str::<Type>(&format!("{}HandlerImpl", snake_to_pascal_case(&handler.c_type)))
303 .expect("Invalid class name in wrapper");
304 return Some(quote! {
305 #new_type
306 });
307 }
308 }
309 None
310 }
311
312 pub fn handle_rs_to_c_return(&self, result: TokenStream, include_field_name: bool) -> TokenStream {
313 if let ArgProcessing::Handler(handler_client) = &self.original.processing {
314 if !self.original.is_mut_pointer() {
315 let handler = handler_client.get(0).unwrap();
316 let handler_name = handler.as_ident();
317 let handler_type = handler.as_type();
318 let clientd_name = handler_client.get(1).unwrap().as_ident();
319 let method_name = format_ident!("{}_callback", handler.c_type);
320 let new_type =
321 parse_str::<Type>(&format!("{}HandlerImpl", snake_to_pascal_case(&self.original.c_type)))
322 .expect("Invalid class name in wrapper");
323 if include_field_name {
324 return quote! {
325 #handler_name: { let callback: #handler_type = if #handler_name.is_none() { None } else { Some(#method_name::<#new_type>) }; callback },
326 #clientd_name: #handler_name.map(|m|m.as_raw()).unwrap_or_else(|| std::ptr::null_mut())
327 };
328 } else {
329 return quote! {
330 { let callback: #handler_type = if #handler_name.is_none() { None } else { Some(#method_name::<#new_type>) }; callback },
331 #handler_name.map(|m|m.as_raw()).unwrap_or_else(|| std::ptr::null_mut())
332 };
333 }
334 } else {
335 return quote! {};
336 }
337 }
338 if let ArgProcessing::StringWithLength(handler_client) = &self.original.processing {
339 if !self.original.is_c_string() {
340 let array = handler_client.get(0).unwrap();
341 let array_name = array.as_ident();
342 let length_name = handler_client.get(1).unwrap().as_ident();
343 if include_field_name {
344 return quote! {
345 #array_name: #array_name.as_ptr() as *const _,
346 #length_name: #array_name.len()
347 };
348 } else {
349 return quote! {
350 #array_name.as_ptr() as *const _,
351 #array_name.len()
352 };
353 }
354 } else {
355 return quote! {};
356 }
357 }
358 if let ArgProcessing::ByteArrayWithLength(handler_client) = &self.original.processing {
359 if !self.original.is_byte_array() {
360 let array = handler_client.get(0).unwrap();
361 let array_name = array.as_ident();
362 let length_name = handler_client.get(1).unwrap().as_ident();
363 if include_field_name {
364 return quote! {
365 #array_name: #array_name.as_ptr() as *mut _,
366 #length_name: #array_name.len()
367 };
368 } else {
369 return quote! {
370 #array_name.as_ptr() as *mut _,
371 #array_name.len()
372 };
373 }
374 } else {
375 return quote! {};
376 }
377 }
378
379 if include_field_name {
380 let arg_name = self.original.as_ident();
381 return if self.original.is_c_string() {
382 quote! {
383 #arg_name: #result.as_ptr()
384 }
385 } else {
386 if self.original.is_single_mut_pointer() && self.original.is_primitive() {
387 return quote! {
388 #arg_name: #result as *mut _
389 };
390 }
391
392 quote! { #arg_name: #result.into() }
393 };
394 }
395
396 if self.original.is_single_mut_pointer() && self.original.is_primitive() {
397 return quote! {
398 #result as *mut _
399 };
400 }
401
402 if self.original.is_c_string() {
403 quote! {
404 #result.as_ptr()
405 }
406 } else {
407 quote! { #result.into() }
408 }
409 }
410}
411
412#[derive(Debug, Clone, Default, Eq, PartialEq)]
413pub struct CWrapper {
414 pub class_name: String,
415 pub type_name: String,
416 pub without_name: String,
417 pub fields: Vec<Arg>,
418 pub methods: Vec<Method>,
419 pub docs: BTreeSet<String>,
420 pub skipped_methods: BTreeSet<String>,
423}
424
425pub fn parse_custom_methods(src: &str) -> HashMap<String, BTreeSet<String>> {
429 let mut result: HashMap<String, BTreeSet<String>> = HashMap::new();
430 let file = syn::parse_file(src).unwrap_or_else(|e| {
431 panic!(
432 "rusteron codegen: failed to parse aeron_custom.rs while extracting custom method \
433 names (this would silently empty the generator skip-list and emit duplicate \
434 methods): {e}"
435 )
436 });
437 for item in &file.items {
438 if let Item::Impl(impl_block) = item {
439 if impl_block.trait_.is_some() {
441 continue;
442 }
443 let type_name = impl_block.self_ty.to_token_stream().to_string();
444 let type_name = type_name.trim().to_string();
445 let entry = result.entry(type_name).or_default();
446 for impl_item in &impl_block.items {
447 if let ImplItem::Fn(method) = impl_item {
448 entry.insert(method.sig.ident.to_string());
449 }
450 }
451 }
452 }
453 result
454}
455
456impl CWrapper {
457 pub fn find_methods(&self, name: &str) -> Vec<Method> {
458 self.methods
459 .iter()
460 .filter(|m| m.struct_method_name == name)
461 .cloned()
462 .collect_vec()
463 }
464
465 pub fn find_unique_method(&self, name: &str) -> Option<Method> {
466 let results = self.find_methods(name);
467 if results.len() == 1 {
468 results.into_iter().next()
469 } else {
470 None
471 }
472 }
473
474 fn get_close_method(&self) -> Option<Method> {
475 self.find_unique_method("close")
476 }
477
478 fn get_is_closed_method(&self) -> Option<Method> {
479 self.find_unique_method("is_closed")
480 }
481
482 fn get_is_closed_method_quote(&self) -> TokenStream {
483 if let Some(method) = self.get_is_closed_method() {
484 let fn_name = format_ident!("{}", method.fn_name);
485 quote! {
486 Some(|c| unsafe{#fn_name(c)})
487 }
488 } else {
489 quote! {
490 None
491 }
492 }
493 }
494
495 fn generate_arg_logging(arguments: &[Arg], arg_names: &[TokenStream]) -> TokenStream {
497 let mut arg_names_idx = 0;
498 let mut arg_names_for_logging = vec![];
499
500 for (arg_idx, arg) in arguments.iter().enumerate() {
501 if arg_names_idx >= arg_names.len() {
502 break;
503 }
504
505 let arg_name_str = &arg.name;
506 let arg_type = arg.as_type();
507 let arg_ident = arg.as_ident();
508
509 match &arg.processing {
511 ArgProcessing::Handler(_) if !arg.is_mut_pointer() => {
512 arg_names_for_logging.push(quote! {
514 concat!(#arg_name_str, ": ", stringify!(#arg_type)).to_string()
515 });
516 arg_names_idx += 2; }
518 ArgProcessing::StringWithLength(_args) => {
519 if arg_idx > 0 && arguments[arg_idx - 1].processing == arg.processing {
521 continue;
522 }
523 arg_names_for_logging.push(quote! {
525 format!("{} = {:?}", #arg_name_str, #arg_ident)
526 });
527 arg_names_idx += 2;
528 }
529 ArgProcessing::ByteArrayWithLength(_args) => {
530 if arg_idx > 0 && arguments[arg_idx - 1].processing == arg.processing {
532 continue;
533 }
534 arg_names_for_logging.push(quote! {
536 format!("{}: {} (len={})", #arg_name_str, stringify!(#arg_type), #arg_ident.len())
537 });
538 arg_names_idx += 2;
539 }
540 _ => {
541 if arg.is_primitive() && !arg.is_any_pointer() {
543 arg_names_for_logging.push(quote! {
544 format!("{} = {:?}", #arg_name_str, #arg_ident)
545 });
546 } else {
547 arg_names_for_logging.push(quote! {
548 concat!(#arg_name_str, ": ", stringify!(#arg_type)).to_string()
549 });
550 }
551 arg_names_idx += 1;
552 }
553 }
554 }
555
556 if arg_names_for_logging.is_empty() {
558 quote! { [""; 0].join(", ") }
559 } else {
560 quote! { [#(#arg_names_for_logging),*].join(", ") }
561 }
562 }
563
564 fn generate_methods(
566 &self,
567 wrappers: &BTreeMap<String, CWrapper>,
568 closure_handlers: &Vec<CHandler>,
569 additional_outer_impls: &mut Vec<TokenStream>,
570 debug_fields: &mut Vec<TokenStream>,
571 ) -> Vec<TokenStream> {
572 self.methods
573 .iter()
574 .filter(|m| !m.arguments.iter().any(|arg| arg.is_double_mut_pointer()))
575 .filter(|m| !self.skipped_methods.contains(&m.struct_method_name))
576 .map(|method| {
577 let set_closed = if method.struct_method_name == "close" {
578 quote! {
579 if let Some(inner) = self.inner.as_owned() {
580 inner.close_already_called.set(true);
581 }
582 }
583 } else {
584 quote! {}
585 };
586
587 let fn_name =
588 Ident::new(&method.struct_method_name, proc_macro2::Span::call_site());
589 let return_type_helper =
590 ReturnType::new(method.return_type.clone(), wrappers.clone());
591 let mut return_type = return_type_helper.get_new_return_type(true, false);
592 let ffi_call = Ident::new(&method.fn_name, proc_macro2::Span::call_site());
593
594 let generic_types: Vec<TokenStream> = method
596 .arguments
597 .iter()
598 .flat_map(|arg| {
599 ReturnType::new(arg.clone(), wrappers.clone())
600 .method_generics_for_where()
601 .into_iter()
602 })
603 .collect_vec();
604 let where_clause = if generic_types.is_empty() {
605 quote! {}
606 } else {
607 quote! { <#(#generic_types),*> }
608 };
609
610 let fn_arguments: Vec<TokenStream> = method
611 .arguments
612 .iter()
613 .filter_map(|arg| {
614 let ty = &arg.c_type;
615 let t = if arg.is_single_mut_pointer() {
616 ty.split(" ").last().unwrap()
617 } else {
618 "notfound"
619 };
620 if let Some(matching_wrapper) = wrappers.get(t) {
621 if matching_wrapper.type_name == self.type_name {
622 None
623 } else {
624 let arg_name = arg.as_ident();
625 let arg_type = ReturnType::new(arg.clone(), wrappers.clone())
626 .get_new_return_type(false, true);
627 if arg_type.is_empty() {
628 None
629 } else {
630 Some(quote! { #arg_name: #arg_type })
631 }
632 }
633 } else {
634 let arg_name = arg.as_ident();
635 let arg_type = ReturnType::new(arg.clone(), wrappers.clone())
636 .get_new_return_type(false, true);
637 if arg_type.is_empty() {
638 None
639 } else {
640 Some(quote! { #arg_name: #arg_type })
641 }
642 }
643 })
644 .filter(|t| !t.is_empty())
645 .collect();
646
647 let mut uses_self = false;
648
649 let mut arg_names: Vec<TokenStream> = method
651 .arguments
652 .iter()
653 .filter_map(|arg| {
654 let ty = &arg.c_type;
655 let t = if arg.is_single_mut_pointer() {
656 ty.split(" ").last().unwrap()
657 } else {
658 "notfound"
659 };
660 if let Some(_matching_wrapper) = wrappers.get(t) {
661 let field_name = arg.as_ident();
662 if ty.ends_with(self.type_name.as_str()) {
663 uses_self = true;
664 Some(quote! { self.get_inner() })
665 } else {
666 Some(quote! { #field_name.get_inner() })
667 }
668 } else {
669 let arg_name = arg.as_ident();
670 let arg_name = quote! { #arg_name };
671 let arg_name = ReturnType::new(arg.clone(), wrappers.clone())
672 .handle_rs_to_c_return(arg_name, false);
673 Some(quote! { #arg_name })
674 }
675 })
676 .filter(|t| !t.is_empty())
677 .collect();
678
679 let converter = return_type_helper.handle_c_to_rs_return(quote! { result }, true, false);
680
681 let mut method_docs: Vec<TokenStream> = get_docs(&method.docs, wrappers, Some(&fn_arguments) );
682
683 let args_log_expr = Self::generate_arg_logging(&method.arguments, &arg_names);
685
686 if uses_self && method.return_type.is_c_string_any() && method.arguments.len() == 1 {
687 let name = format_ident!("{}", method.struct_method_name);
688 debug_fields.push( quote! {
689 .field(stringify!(#name), &self.#name() )
690 } );
691 }
692
693 let possible_self = if uses_self {
694 quote! { &self, }
695 } else {
696 if return_type.to_string().eq("& str") {
697 return_type = quote! { &'static str };
698 method_docs.push(quote! {#[doc = "SAFETY: this is static for performance reasons, so you should not store this without copying it!!"]});
699 }
700 quote! {}
701 };
702
703
704
705 let mut additional_methods = vec![];
706
707 Self::add_mut_string_methods_if_applicable(method, &fn_name, uses_self, &method_docs, &mut additional_methods);
708
709 Self::add_getter_instead_of_mut_arg_if_applicable(wrappers, method, &fn_name, &where_clause, &possible_self, &method_docs, &mut additional_methods, debug_fields);
711
712 Self::add_once_methods_for_handlers(closure_handlers, method, &fn_name, &return_type, &ffi_call, &where_clause, &fn_arguments, &mut arg_names, &converter, &possible_self, &method_docs, &mut additional_methods, &set_closed);
713
714 let mut_primitivies = method.arguments.iter()
715 .filter(|a| a.is_mut_pointer() && a.is_primitive())
716 .collect_vec();
717 let single_mut_field = method.return_type.is_c_raw_int() && mut_primitivies.len() == 1;
718
719 if single_mut_field {
722 let mut_field = mut_primitivies.first().unwrap();
723 let rt: Type = parse_str(mut_field.c_type.split_whitespace().last().unwrap()).unwrap();
724 let return_type = quote! { Result<#rt, AeronCError> };
725
726 let fn_arguments= fn_arguments.into_iter().filter(|arg| {!arg.to_string().contains("& mut ")})
727 .collect_vec();
728
729 let idx = arg_names.iter().enumerate()
730 .filter(|(_, arg)| arg.to_string().ends_with("* mut _"))
731 .map(|(i, _)| i)
732 .next().unwrap();
733
734 arg_names[idx] = quote! { &mut mut_result };
735
736 let mut first = true;
737 let mut method_docs = method_docs.iter()
738 .filter(|d| !d.to_string().contains("# Return"))
739 .map(|d| {
740 let mut string = d.to_string();
741 string = string.replace("# Parameters", "");
742 if string.contains("out param") {
743 TokenStream::from_str(&string.replace("- `", "\n# Return\n`")).unwrap()
744 } else {
745 if string.contains("- `") && first {
746 first = false;
747 string = string.replacen("- `","# Parameters\n- `", 1);
748 }
749 TokenStream::from_str(&string).unwrap()
750 }
751 })
752 .collect_vec();
753
754 let filter_param_title = !method_docs.iter().any(|d| d.to_string().contains("- `"));
755
756 if filter_param_title {
757 method_docs = method_docs.into_iter()
758 .map(|s| TokenStream::from_str(s.to_string().replace("# Parameters\n", "").as_str()).unwrap())
759 .collect_vec();
760 }
761
762
763 quote! {
764 #[inline]
765 #(#method_docs)*
766 pub fn #fn_name #where_clause(#possible_self #(#fn_arguments),*) -> #return_type {
767 #set_closed
768 unsafe {
769 let mut mut_result: #rt = Default::default();
770
771 #[cfg(feature = "log-c-bindings")]
772 log::info!(
773 "{}({})",
774 stringify!(#ffi_call),
775 #args_log_expr
776 );
777
778 let err_code = #ffi_call(#(#arg_names),*);
779
780 #[cfg(feature = "log-c-bindings")]
781 log::info!(" -> err_code = {:?}, result = {:?}", err_code, mut_result);
782
783 if err_code < 0 {
784 return Err(AeronCError::from_code(err_code));
785 } else {
786 return Ok(mut_result);
787 }
788 }
789 }
790
791 #(#additional_methods)*
792 }
793 } else {
794 quote! {
795 #[inline]
796 #(#method_docs)*
797 pub fn #fn_name #where_clause(#possible_self #(#fn_arguments),*) -> #return_type {
798 #set_closed
799 unsafe {
800 #[cfg(feature = "log-c-bindings")]
801 log::info!(
802 "{}({})",
803 stringify!(#ffi_call),
804 #args_log_expr
805 );
806
807 let result = #ffi_call(#(#arg_names),*);
808
809 #[cfg(feature = "log-c-bindings")]
810 log::info!(" -> {:?}", result);
811
812 #converter
813 }
814 }
815
816 #(#additional_methods)*
817 }
818 }
819 })
820 .collect()
821 }
822
823 fn add_once_methods_for_handlers(
824 closure_handlers: &Vec<CHandler>,
825 method: &Method,
826 fn_name: &Ident,
827 return_type: &TokenStream,
828 ffi_call: &Ident,
829 where_clause: &TokenStream,
830 fn_arguments: &Vec<TokenStream>,
831 arg_names: &mut Vec<TokenStream>,
832 converter: &TokenStream,
833 possible_self: &TokenStream,
834 method_docs: &Vec<TokenStream>,
835 additional_methods: &mut Vec<TokenStream>,
836 set_closed: &TokenStream,
837 ) {
838 if method.arguments.iter().any(|arg| {
839 matches!(arg.processing, ArgProcessing::Handler(_))
840 && !method.fn_name.starts_with("set_")
841 && !method.fn_name.starts_with("add_")
842 }) {
843 let fn_name = format_ident!("{}_once", fn_name);
844
845 let mut where_clause = where_clause.to_string();
847
848 for c in closure_handlers.iter() {
849 if !c.closure_type_name.is_empty() {
850 where_clause =
851 where_clause.replace(&c.closure_type_name.to_string(), &c.fn_mut_signature.to_string());
852 }
853 }
854 let where_clause = parse_str::<TokenStream>(&where_clause).unwrap();
855
856 let fn_arguments = fn_arguments.iter().map(|arg| {
858 let mut arg = arg.clone();
859 let str = arg.to_string();
860 if str.contains("& Handler ") {
861 let parts = str.split(" ").collect_vec();
863 let variable_name = parse_str::<TokenStream>(parts[0]).unwrap();
864 let closure_type = parse_str::<TokenStream>(parts[parts.len() - 2]).unwrap();
865 arg = quote! { mut #variable_name : #closure_type };
866 }
867
868 arg
869 });
870
871 let arg_names = arg_names.iter().map(|x| {
873 let mut str = x.to_string()
874 .replace("_callback :: <", "_callback_for_once_closure :: <")
875 ;
876
877 if str.contains("_callback_for_once_closure") {
878 let caps = regex::Regex::new(
895 r#"let callback\s*:\s*(?P<type>[\w_]+)\s*=\s*if\s*(?P<handler_var_name>[\w_]+)\s*\.\s*is_none\s*\(\).*Some\s*\(\s*(?P<callback>[\w_]+)\s*::\s*<\s*(?P<handler>[\w_]+)\s*>\s*\).*"#
896 )
897 .unwrap()
898 .captures(&str)
899 .expect(&format!("regex failed for {str}"));
900 let func_type = parse_str::<TokenStream>(&caps["type"]).unwrap();
901 let handler_var_name = parse_str::<TokenStream>(&caps["handler_var_name"]).unwrap();
902 let callback = parse_str::<TokenStream>(&caps["callback"]).unwrap();
903 let handler_type = parse_str::<TokenStream>(&caps["handler"]).unwrap();
904
905 let new_code = quote! {
906 Some(#callback::<#handler_type>),
907 &mut #handler_var_name as *mut _ as *mut std::os::raw::c_void
908 };
909 str = new_code.to_string();
910 }
911
912 parse_str::<TokenStream>(&str).unwrap()
913 }).collect_vec();
914
915 let args_log_expr = Self::generate_arg_logging(&method.arguments, &arg_names);
917
918 additional_methods.push(quote! {
919 #[inline]
920 #(#method_docs)*
921 pub fn #fn_name #where_clause(#possible_self #(#fn_arguments),*) -> #return_type {
926 #set_closed
927 unsafe {
928 #[cfg(feature = "log-c-bindings")]
929 log::info!(
930 "{}({})",
931 stringify!(#ffi_call),
932 #args_log_expr
933 );
934
935 let result = #ffi_call(#(#arg_names),*);
936
937 #[cfg(feature = "log-c-bindings")]
938 log::info!(" -> {:?}", result);
939
940 #converter
941 }
942 }
943 })
944 }
945 }
946
947 fn add_getter_instead_of_mut_arg_if_applicable(
948 wrappers: &BTreeMap<String, CWrapper>,
949 method: &Method,
950 fn_name: &Ident,
951 where_clause: &TokenStream,
952 possible_self: &TokenStream,
953 method_docs: &Vec<TokenStream>,
954 additional_methods: &mut Vec<TokenStream>,
955 debug_fields: &mut Vec<TokenStream>,
956 ) {
957 if ["constants", "buffers", "values"]
958 .iter()
959 .any(|name| method.struct_method_name == *name)
960 && method.arguments.len() == 2
961 {
962 let rt = ReturnType::new(method.arguments[1].clone(), wrappers.clone());
963 let return_type = rt.get_new_return_type(false, false);
964 let getter_method = format_ident!("get_{}", fn_name);
965 let method_docs = method_docs
966 .iter()
967 .cloned()
968 .take_while(|t| !t.to_string().contains(" Parameter"))
969 .collect_vec();
970 additional_methods.push(quote! {
971 #[inline]
972 #(#method_docs)*
973 pub fn #getter_method #where_clause(#possible_self) -> Result<#return_type, AeronCError> {
974 let result = #return_type::new_zeroed_on_stack();
975 self.#fn_name(&result)?;
976 Ok(result)
977 }
978 });
979 debug_fields.push(quote! {
980 .field(stringify!(#fn_name), &self.#getter_method() )
981 });
982 }
983 }
984
985 fn add_mut_string_methods_if_applicable(
986 method: &Method,
987 fn_name: &Ident,
988 uses_self: bool,
989 method_docs: &Vec<TokenStream>,
990 additional_methods: &mut Vec<TokenStream>,
991 ) {
992 if method.arguments.len() == 3 && uses_self {
993 let method_docs = method_docs.clone();
994 let into_method = format_ident!("{}_into", fn_name);
995 if method.arguments[1].is_mut_c_string() && method.arguments[2].is_usize() {
996 let string_method = format_ident!("{}_as_string", fn_name);
997 additional_methods.push(quote! {
998 #[inline]
999 #(#method_docs)*
1000 pub fn #string_method(
1001 &self,
1002 max_length: usize,
1003 ) -> Result<String, AeronCError> {
1004 let mut result = String::with_capacity(max_length);
1005 self.#into_method(&mut result)?;
1006 Ok(result)
1007 }
1008
1009 #[inline]
1010 #(#method_docs)*
1011 #[doc = "NOTE: allocation friendly method, the string capacity must be set as it will truncate string to capacity it will never grow the string. So if you pass String::new() it will write 0 chars"]
1012 pub fn #into_method(
1013 &self,
1014 dst_truncate_to_capacity: &mut String,
1015 ) -> Result<i32, AeronCError> {
1016 unsafe {
1017 let capacity = dst_truncate_to_capacity.capacity();
1018 let vec = dst_truncate_to_capacity.as_mut_vec();
1019 vec.set_len(capacity);
1020 let result = self.#fn_name(vec.as_mut_ptr() as *mut _, capacity)?;
1021 let mut len = 0;
1022 loop {
1023 if len == capacity {
1024 break;
1025 }
1026 let val = vec[len];
1027 if val == 0 {
1028 break;
1029 }
1030 len += 1;
1031 }
1032 vec.set_len(len);
1033 Ok(result)
1034 }
1035 }
1036 });
1037 }
1038 }
1039 }
1040
1041 fn generate_fields(
1043 &self,
1044 cwrappers: &BTreeMap<String, CWrapper>,
1045 debug_fields: &mut Vec<TokenStream>,
1046 ) -> Vec<TokenStream> {
1047 self.fields
1048 .iter()
1049 .filter(|arg| {
1050 !arg.name.starts_with("_") && !self.methods.iter().any(|m| m.struct_method_name.as_str() == arg.name)
1051 })
1052 .map(|arg| {
1053 let field_name = &arg.name;
1054 let fn_name = Ident::new(field_name, proc_macro2::Span::call_site());
1055
1056 let mut arg = arg.clone();
1057 if arg.is_mut_c_string() {
1059 arg.c_type = arg.c_type.replace(" mut ", " const ");
1060 }
1061 let mut rt = ReturnType::new(arg.clone(), cwrappers.clone());
1062 let mut return_type = rt.get_new_return_type(false, false);
1063 let handler = if let ArgProcessing::Handler(_) = &arg.processing {
1064 true
1065 } else {
1066 false
1067 };
1068 if return_type.is_empty() || handler {
1069 rt = ReturnType::new(
1070 Arg {
1071 processing: ArgProcessing::Default,
1072 ..arg.clone()
1073 },
1074 cwrappers.clone(),
1075 );
1076 return_type = rt.get_new_return_type(false, false);
1077 }
1078 let converter = rt.handle_c_to_rs_return(quote! { self.#fn_name }, false, true);
1079
1080 if rt.original.is_primitive()
1081 || rt.original.is_c_string_any()
1082 || rt.original.is_byte_array()
1083 || cwrappers.contains_key(&rt.original.c_type)
1084 {
1085 if !rt.original.is_any_pointer() || rt.original.is_c_string_any() {
1086 debug_fields.push(quote! { .field(stringify!(#fn_name), &self.#fn_name()) });
1087 }
1088 }
1089
1090 quote! {
1091 #[inline]
1092 pub fn #fn_name(&self) -> #return_type {
1093 #converter
1094 }
1095 }
1096 })
1097 .filter(|t| !t.is_empty())
1098 .collect()
1099 }
1100
1101 fn generate_constructor(
1103 &self,
1104 wrappers: &BTreeMap<String, CWrapper>,
1105 constructor_fields: &mut Vec<TokenStream>,
1106 new_ref_set_none: &mut Vec<TokenStream>,
1107 ) -> Vec<TokenStream> {
1108 let constructors = self
1109 .methods
1110 .iter()
1111 .filter(|m| m.arguments.iter().any(|arg| arg.is_double_mut_pointer()))
1112 .map(|method| {
1113 let init_fn = format_ident!("{}", method.fn_name);
1114 let close_method = self.find_close_method(method);
1115 let found_close = close_method.is_some()
1116 && close_method.unwrap().return_type.is_c_raw_int()
1117 && close_method.unwrap() != method
1118 && close_method
1119 .unwrap()
1120 .arguments
1121 .iter()
1122 .skip(1)
1123 .all(|a| method.arguments.iter().any(|a2| a.name == a2.name));
1124 if found_close {
1125 let close_fn = format_ident!("{}", close_method.unwrap().fn_name);
1126 let init_args: Vec<TokenStream> = method
1127 .arguments
1128 .iter()
1129 .enumerate()
1130 .map(|(idx, arg)| {
1131 if idx == 0 {
1132 quote! { ctx_field }
1133 } else {
1134 let arg_name = arg.as_ident();
1135 quote! { #arg_name }
1136 }
1137 })
1138 .filter(|t| !t.is_empty())
1139 .collect();
1140 let close_args: Vec<TokenStream> = close_method
1141 .unwrap_or(method)
1142 .arguments
1143 .iter()
1144 .enumerate()
1145 .map(|(idx, arg)| {
1146 if idx == 0 {
1147 if arg.is_double_mut_pointer() {
1148 quote! { ctx_field }
1149 } else {
1150 quote! { *ctx_field }
1151 }
1152 } else {
1153 let arg_name = arg.as_ident();
1154 quote! { #arg_name.into() }
1155 }
1156 })
1157 .filter(|t| !t.is_empty())
1158 .collect();
1159 let lets: Vec<TokenStream> = Self::lets_for_copying_arguments(wrappers, &method.arguments, true);
1160
1161 constructor_fields.clear();
1162 constructor_fields.extend(Self::constructor_fields(wrappers, &method.arguments, &self.class_name));
1163
1164 let new_ref_args = Self::new_args(wrappers, &method.arguments, &self.class_name, false);
1165
1166 new_ref_set_none.clear();
1167 new_ref_set_none.extend(Self::new_args(wrappers, &method.arguments, &self.class_name, true));
1168
1169 let new_args: Vec<TokenStream> = method
1170 .arguments
1171 .iter()
1172 .enumerate()
1173 .filter_map(|(_idx, arg)| {
1174 if arg.is_double_mut_pointer() {
1175 None
1176 } else {
1177 let arg_name = arg.as_ident();
1178 let arg_type =
1179 ReturnType::new(arg.clone(), wrappers.clone()).get_new_return_type(false, true);
1180 if arg_type.clone().into_token_stream().is_empty() {
1181 None
1182 } else {
1183 Some(quote! { #arg_name: #arg_type })
1184 }
1185 }
1186 })
1187 .filter(|t| !t.is_empty())
1188 .collect();
1189
1190 let fn_name = format_ident!(
1191 "{}",
1192 method
1193 .struct_method_name
1194 .replace("init", "new")
1195 .replace("create", "new")
1196 );
1197
1198 let generic_types: Vec<TokenStream> = method
1199 .arguments
1200 .iter()
1201 .flat_map(|arg| {
1202 ReturnType::new(arg.clone(), wrappers.clone())
1203 .method_generics_for_where()
1204 .into_iter()
1205 })
1206 .collect_vec();
1207 let where_clause = if generic_types.is_empty() {
1208 quote! {}
1209 } else {
1210 quote! { <#(#generic_types),*> }
1211 };
1212
1213 let method_docs: Vec<TokenStream> = get_docs(&method.docs, wrappers, Some(&new_args));
1214
1215 let init_log_expr_tokens = Self::generate_arg_logging(&method.arguments, &init_args);
1217 let close_log_expr_tokens = if let Some(close_m) = close_method {
1219 Self::generate_arg_logging(&close_m.arguments, &close_args)
1220 } else {
1221 quote! { "" }
1222 };
1223
1224 let is_closed_method = self.get_is_closed_method_quote();
1225 quote! {
1226 #(#method_docs)*
1227 pub fn #fn_name #where_clause(#(#new_args),*) -> Result<Self, AeronCError> {
1228 #(#lets)*
1229 let resource_constructor = ManagedCResource::new(
1231 move |ctx_field| unsafe {
1232 #[cfg(feature = "log-c-bindings")]
1233 {
1234 let log_args = #init_log_expr_tokens;
1235 log::info!("{}({})", stringify!(#init_fn), log_args);
1236 }
1237 #init_fn(#(#init_args),*)
1238 },
1239 Some(Box::new(move |ctx_field| unsafe {
1240 #[cfg(feature = "log-c-bindings")]
1241 {
1242 let log_args = #close_log_expr_tokens;
1243 log::info!("{}({})", stringify!(#close_fn), log_args);
1244 }
1245 #close_fn(#(#close_args),*)
1246 } )),
1247 false,
1248 #is_closed_method,
1249 )?;
1250
1251 Ok(Self {
1252 inner: CResource::OwnedOnHeap(std::rc::Rc::new(resource_constructor)),
1253 #(#new_ref_args)*
1254 })
1255 }
1256 }
1257 } else {
1258 quote! {}
1259 }
1260 })
1261 .collect_vec();
1262
1263 let no_constructor = constructors.iter().map(|x| x.to_string()).join("").trim().is_empty();
1264 if no_constructor {
1265 let type_name = format_ident!("{}", self.type_name);
1266 let is_closed_method = self.get_is_closed_method_quote();
1267
1268 let zeroed_impl = quote! {
1269 #[inline]
1270 pub fn new_zeroed_on_heap() -> Self {
1272 let resource = ManagedCResource::new(
1273 move |ctx_field| {
1274 #[cfg(feature = "extra-logging")]
1275 log::info!("creating zeroed empty resource on heap {}", stringify!(#type_name));
1276 let inst: #type_name = unsafe { std::mem::zeroed() };
1277 let inner_ptr: *mut #type_name = Box::into_raw(Box::new(inst));
1278 unsafe { *ctx_field = inner_ptr };
1279 0
1280 },
1281 None,
1282 true,
1283 #is_closed_method
1284 ).unwrap();
1285
1286 Self {
1287 inner: CResource::OwnedOnHeap(std::rc::Rc::new(resource)),
1288 }
1289 }
1290
1291 #[inline]
1292 pub fn new_zeroed_on_stack() -> Self {
1295 #[cfg(feature = "extra-logging")]
1296 log::debug!("creating zeroed empty resource on stack {}", stringify!(#type_name));
1297
1298 Self {
1299 inner: CResource::OwnedOnStack(std::mem::MaybeUninit::zeroed()),
1300 }
1301 }
1302 };
1303 if self.has_default_method() {
1304 let type_name = format_ident!("{}", self.type_name);
1305 let new_args: Vec<TokenStream> = self
1306 .fields
1307 .iter()
1308 .filter_map(|arg| {
1309 let arg_name = arg.as_ident();
1310 let arg_type = ReturnType::new(arg.clone(), wrappers.clone()).get_new_return_type(false, true);
1311 if arg_type.is_empty() {
1312 None
1313 } else {
1314 Some(quote! { #arg_name: #arg_type })
1315 }
1316 })
1317 .filter(|t| !t.is_empty())
1318 .collect();
1319 let init_args: Vec<TokenStream> = self
1320 .fields
1321 .iter()
1322 .map(|arg| {
1323 let arg_name = arg.as_ident();
1324 let value = ReturnType::new(arg.clone(), wrappers.clone())
1325 .handle_rs_to_c_return(quote! { #arg_name }, true);
1326 quote! { #value }
1327 })
1328 .filter(|t| !t.is_empty())
1329 .collect();
1330
1331 let generic_types: Vec<TokenStream> = self
1332 .fields
1333 .iter()
1334 .flat_map(|arg| {
1335 ReturnType::new(arg.clone(), wrappers.clone())
1336 .method_generics_for_where()
1337 .into_iter()
1338 })
1339 .collect_vec();
1340 let where_clause = if generic_types.is_empty() {
1341 quote! {}
1342 } else {
1343 quote! { <#(#generic_types),*> }
1344 };
1345
1346 let cloned_fields = self
1347 .fields
1348 .iter()
1349 .filter(|a| a.processing == ArgProcessing::Default)
1350 .cloned()
1351 .collect_vec();
1352 let lets: Vec<TokenStream> = Self::lets_for_copying_arguments(wrappers, &cloned_fields, false);
1353
1354 let is_closed_method = self.get_is_closed_method_quote();
1355
1356 vec![quote! {
1357 #[inline]
1358 pub fn new #where_clause(#(#new_args),*) -> Result<Self, AeronCError> {
1359 #(#lets)*
1360 let r_constructor = ManagedCResource::new(
1362 move |ctx_field| {
1363 let inst = #type_name { #(#init_args),* };
1364 let inner_ptr: *mut #type_name = Box::into_raw(Box::new(inst));
1365 unsafe { *ctx_field = inner_ptr };
1366 0
1367 },
1368 None,
1369 true,
1370 #is_closed_method
1371 )?;
1372
1373 Ok(Self {
1374 inner: CResource::OwnedOnHeap(std::rc::Rc::new(r_constructor)),
1375 })
1376 }
1377
1378 #zeroed_impl
1379 }]
1380 } else {
1381 vec![zeroed_impl]
1382 }
1383 } else {
1384 constructors
1385 }
1386 }
1387
1388 fn lets_for_copying_arguments(
1389 wrappers: &BTreeMap<String, CWrapper>,
1390 arguments: &Vec<Arg>,
1391 include_let_statements: bool,
1392 ) -> Vec<TokenStream> {
1393 arguments
1394 .iter()
1395 .enumerate()
1396 .filter_map(|(_idx, arg)| {
1397 if arg.is_double_mut_pointer() {
1398 None
1399 } else {
1400 let arg_name = arg.as_ident();
1401 let rtype = arg.as_type();
1402
1403 let fields = if arg.is_single_mut_pointer()
1405 && wrappers.contains_key(arg.c_type.split_whitespace().last().unwrap())
1406 {
1407 let arg_copy = format_ident!("{}_copy", arg.name);
1408 quote! {
1409 let #arg_copy = #arg_name.clone();
1410 }
1411 } else {
1412 quote! {}
1413 };
1414
1415 let return_type = ReturnType::new(arg.clone(), wrappers.clone());
1416
1417 if let ArgProcessing::StringWithLength(_args) | ArgProcessing::ByteArrayWithLength(_args) =
1418 &return_type.original.processing
1419 {
1420 return None;
1421 }
1422 if let ArgProcessing::Handler(args) = &return_type.original.processing {
1423 let arg1 = args[0].as_ident();
1424 let arg2 = args[1].as_ident();
1425 let value = return_type.handle_rs_to_c_return(quote! { #arg_name }, false);
1426
1427 if value.is_empty() {
1428 return None;
1429 }
1430
1431 if include_let_statements {
1432 return Some(quote! { #fields let (#arg1, #arg2)= (#value); });
1433 } else {
1434 return Some(fields);
1435 }
1436 }
1437
1438 let value = return_type.handle_rs_to_c_return(quote! { #arg_name }, false);
1439 if value.is_empty() {
1440 None
1441 } else {
1442 if include_let_statements {
1443 Some(quote! { #fields let #arg_name: #rtype = #value; })
1444 } else {
1445 return Some(fields);
1446 }
1447 }
1448 }
1449 })
1450 .filter(|t| !t.is_empty())
1451 .collect()
1452 }
1453
1454 fn constructor_fields(
1455 wrappers: &BTreeMap<String, CWrapper>,
1456 arguments: &Vec<Arg>,
1457 class_name: &String,
1458 ) -> Vec<TokenStream> {
1459 if class_name == "AeronAsyncDestination" {
1460 return vec![];
1461 }
1462
1463 arguments
1464 .iter()
1465 .enumerate()
1466 .filter_map(|(_idx, arg)| {
1467 if arg.is_double_mut_pointer() {
1468 None
1469 } else {
1470 let arg_name = arg.as_ident();
1471 let rtype = arg.as_type();
1472 if arg.is_single_mut_pointer()
1473 && wrappers.contains_key(arg.c_type.split_whitespace().last().unwrap())
1474 {
1475 let return_type = ReturnType::new(arg.clone(), wrappers.clone());
1476 let return_type = return_type.get_new_return_type(false, false);
1477
1478 let arg_copy = format_ident!("_{}", arg.name);
1479 Some(quote! {
1480 #arg_copy: Option<#return_type>,
1481 })
1482 } else {
1483 None
1484 }
1485 }
1486 })
1487 .collect()
1488 }
1489
1490 fn new_args(
1491 wrappers: &BTreeMap<String, CWrapper>,
1492 arguments: &Vec<Arg>,
1493 class_name: &String,
1494 set_none: bool,
1495 ) -> Vec<TokenStream> {
1496 if class_name == "AeronAsyncDestination" {
1497 return vec![];
1498 }
1499
1500 arguments
1501 .iter()
1502 .enumerate()
1503 .filter_map(|(_idx, arg)| {
1504 if arg.is_double_mut_pointer() {
1505 None
1506 } else {
1507 let arg_name = arg.as_ident();
1508 let rtype = arg.as_type();
1509 if arg.is_single_mut_pointer()
1510 && wrappers.contains_key(arg.c_type.split_whitespace().last().unwrap())
1511 {
1512 let arg_f = format_ident!("_{}", &arg.name);
1513 let arg_copy = format_ident!("{}_copy", &arg.name);
1514 if set_none {
1515 Some(quote! {
1516 #arg_f: None,
1517 })
1518 } else {
1519 Some(quote! {
1520 #arg_f: Some(#arg_copy),
1521 })
1522 }
1523 } else {
1524 None
1525 }
1526 }
1527 })
1528 .collect()
1529 }
1530
1531 fn find_close_method(&self, method: &Method) -> Option<&Method> {
1532 let mut close_method = None;
1533
1534 if ["_init", "_create", "_add"]
1536 .iter()
1537 .all(|find| !method.fn_name.contains(find))
1538 {
1539 return None;
1540 }
1541
1542 for name in ["_destroy", "_delete"] {
1543 let close_fn = format_ident!(
1544 "{}",
1545 method
1546 .fn_name
1547 .replace("_init", "_close")
1548 .replace("_create", name)
1549 .replace("_add_", "_remove_")
1550 );
1551 let method = self.methods.iter().find(|m| close_fn.to_string().contains(&m.fn_name));
1552 if method.is_some() {
1553 close_method = method;
1554 break;
1555 }
1556 }
1557 close_method
1558 }
1559
1560 fn has_default_method(&self) -> bool {
1561 let no_init_method = !self.methods.iter().any(|m| {
1563 m.arguments
1564 .iter()
1565 .any(|arg| arg.is_double_mut_pointer() || (arg.is_single_mut_pointer() && m.fn_name.contains("_init_")))
1566 });
1567
1568 no_init_method && !self.fields.iter().any(|arg| arg.name.starts_with("_")) && !self.fields.is_empty()
1569 }
1570
1571 fn generate_allocation_test(&self) -> TokenStream {
1572 let class_name = format_ident!("{}", self.class_name);
1573
1574 let has_c_constructor = self
1575 .methods
1576 .iter()
1577 .any(|m| m.arguments.iter().any(|arg| arg.is_double_mut_pointer()));
1578 let has_empty_new_constructor = self.methods.iter().any(|m| {
1579 m.fn_name.contains("_init_")
1580 && m.arguments.iter().any(|arg| arg.is_double_mut_pointer())
1581 && m.arguments.len() == 1
1582 });
1583
1584 let mut tests = vec![];
1585
1586 if !has_c_constructor {
1587 tests.push(quote! {
1588 #[test]
1589 #[file_serial(global)]
1590 fn test_new_on_stack() {
1591 crate::test_alloc::assert_no_allocation(|| {
1592 for _ in 0..100 {
1593 let _ = #class_name::new_zeroed_on_stack();
1594 }
1595 });
1596 }
1597 });
1598 }
1599
1600 if has_empty_new_constructor {
1601 tests.push(quote! {
1602 #[test]
1603 #[file_serial(global)]
1604 fn test_new() {
1605 crate::test_alloc::assert_no_allocation(|| {
1606 for _ in 0..100 {
1607 let _ = #class_name::new();
1608 }
1609 });
1610 }
1611 });
1612 }
1613
1614 if self.has_default_method() {
1615 tests.push(quote! {
1616 #[test]
1617 #[file_serial(global)]
1618 fn test_default() {
1619 crate::test_alloc::assert_no_allocation(|| {
1620 for _ in 0..100 {
1621 let _ = #class_name::default();
1622 }
1623 });
1624 }
1625 });
1626 }
1627
1628 let mod_name = format_ident!("{}_allocation_tests", self.type_name);
1629
1630 if tests.is_empty() {
1631 quote! {}
1632 } else {
1633 quote! {
1634 #[cfg(test)]
1635 mod #mod_name {
1636 use super::*;
1637 use serial_test::file_serial;
1638 #(#tests)*
1639 }
1640 }
1641 }
1642 }
1643}
1644
1645#[cfg(test)]
1646mod parse_custom_methods_tests {
1647 use super::parse_custom_methods;
1648 use std::collections::BTreeSet;
1649
1650 #[test]
1651 fn extracts_method_names_from_inherent_impls() {
1652 let src = r#"
1653 impl AeronPublication {
1654 pub fn offer_result(&self) -> i64 { 0 }
1655 pub fn status(&self) -> u8 { 0 }
1656 }
1657 impl AeronSubscription {
1658 pub fn status(&self) -> u8 { 0 }
1659 }
1660 "#;
1661 let map = parse_custom_methods(src);
1662 assert_eq!(
1663 map.get("AeronPublication"),
1664 Some(
1665 &["offer_result", "status"]
1666 .iter()
1667 .map(|s| s.to_string())
1668 .collect::<BTreeSet<_>>()
1669 )
1670 );
1671 assert!(map.get("AeronSubscription").map_or(false, |s| s.contains("status")));
1672 }
1673
1674 #[test]
1675 fn ignores_trait_impls() {
1676 let src = r#"
1679 impl std::fmt::Display for AeronCError {
1680 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Ok(()) }
1681 }
1682 "#;
1683 let map = parse_custom_methods(src);
1684 assert!(
1685 !map.contains_key("AeronCError"),
1686 "trait impls must not appear in the skip-list"
1687 );
1688 }
1689
1690 #[test]
1691 #[should_panic(expected = "failed to parse aeron_custom.rs")]
1692 fn panics_loudly_on_malformed_input() {
1693 let _ = parse_custom_methods("impl { not valid rust }}}");
1695 }
1696
1697 #[test]
1698 fn empty_input_yields_empty_map() {
1699 assert!(parse_custom_methods("").is_empty());
1700 }
1701
1702 #[test]
1703 fn self_type_keyed_by_plain_token_stream() {
1704 let src = r#"
1705 impl AeronPublication { pub fn offer_result(&self) -> i64 { 0 } }
1706 "#;
1707 let map = parse_custom_methods(src);
1708 assert_eq!(map.len(), 1);
1710 assert!(map.contains_key("AeronPublication"));
1711 }
1712}
1713
1714#[cfg(test)]
1715mod arg_classification_tests {
1716 use super::{Arg, ArgProcessing};
1717
1718 fn arg(c_type: &str) -> Arg {
1719 Arg {
1720 name: "x".to_string(),
1721 c_type: c_type.to_string(),
1722 processing: ArgProcessing::Default,
1723 }
1724 }
1725
1726 #[test]
1727 fn classifies_c_strings() {
1728 assert!(arg("* const :: std :: os :: raw :: c_char").is_c_string());
1729 assert!(arg("* const :: std :: os :: raw :: c_char").is_c_string_any());
1730 assert!(arg("* mut :: std :: os :: raw :: c_char").is_mut_c_string());
1731 assert!(arg("* mut :: std :: os :: raw :: c_char").is_c_string_any());
1732 assert!(!arg("* const u8").is_c_string());
1734 assert!(!arg("i32").is_c_string_any());
1735 }
1736
1737 #[test]
1738 fn classifies_byte_arrays() {
1739 assert!(arg("* const u8").is_byte_array());
1740 assert!(arg("* mut u8").is_byte_array());
1741 assert!(arg("* mut u8").is_mut_byte_array());
1742 assert!(!arg("* const u8").is_mut_byte_array());
1743 assert!(!arg("* const :: std :: os :: raw :: c_char").is_byte_array());
1744 }
1745
1746 #[test]
1747 fn classifies_raw_int_return() {
1748 assert!(arg(":: std :: os :: raw :: c_int").is_c_raw_int());
1749 assert!(!arg("i32").is_c_raw_int());
1750 }
1751
1752 #[test]
1753 fn classifies_void_pointer() {
1754 assert!(arg("* mut :: std :: os :: raw :: c_void").is_c_void());
1755 assert!(!arg("* mut u8").is_c_void());
1756 }
1757
1758 #[test]
1759 fn classifies_mut_pointers_single_vs_double() {
1760 assert!(arg("* mut i32").is_mut_pointer());
1762 assert!(arg("* mut i32").is_single_mut_pointer());
1763 assert!(!arg("* mut i32").is_double_mut_pointer());
1764 assert!(arg("* mut * mut aeron_foo_t").is_mut_pointer());
1766 assert!(arg("* mut * mut aeron_foo_t").is_double_mut_pointer());
1767 assert!(!arg("* mut * mut aeron_foo_t").is_single_mut_pointer());
1768 assert!(!arg("* const i32").is_mut_pointer());
1770 }
1771
1772 #[test]
1773 fn classifies_primitives() {
1774 for ty in [
1775 "i64", "u64", "f32", "f64", "i32", "i16", "u32", "u16", "bool", "usize", "isize",
1776 ] {
1777 assert!(arg(ty).is_primitive(), "{ty} should be primitive");
1778 }
1779 assert!(arg("* mut i32").is_primitive());
1784 assert!(!arg("* mut aeron_foo_t").is_primitive());
1786 }
1787
1788 #[test]
1789 fn classifies_any_pointer() {
1790 assert!(arg("* const i32").is_any_pointer());
1791 assert!(arg("* mut i32").is_any_pointer());
1792 assert!(!arg("i32").is_any_pointer());
1793 }
1794}
1795
1796fn get_docs(
1797 docs: &BTreeSet<String>,
1798 wrappers: &BTreeMap<String, CWrapper>,
1799 arguments: Option<&Vec<TokenStream>>,
1800) -> Vec<TokenStream> {
1801 let mut first_param = true;
1802 docs.iter()
1803 .flat_map(|d| d.lines())
1804 .filter(|s| {
1805 arguments.is_none()
1806 || !s.contains("@param")
1807 || (s.contains("@param")
1808 && arguments
1809 .unwrap()
1810 .iter()
1811 .any(|a| s.contains(format!(" {}", a.to_string().split_whitespace().next().unwrap()).as_str())))
1812 })
1813 .map(|doc| {
1814 let mut doc = doc.to_string();
1815
1816 if first_param && doc.contains("@param") {
1817 doc = format!("# Parameters\n{}", doc);
1818 first_param = false;
1819 }
1820
1821 if doc.contains("@param") {
1822 doc = regex::Regex::new("@param\\s+([^ ]+)")
1823 .unwrap()
1824 .replace(doc.as_str(), "\n - `$1`")
1825 .to_string();
1826 }
1827
1828 doc = doc
1829 .replace("@return", "\n# Return\n")
1830 .replace("<p>", "\n")
1831 .replace("</p>", "\n");
1832
1833 doc = wrappers
1834 .values()
1835 .fold(doc, |acc, v| acc.replace(&v.type_name, &format!("`{}`", v.class_name)));
1836
1837 if doc.contains("@deprecated") {
1838 quote! {
1839 #[deprecated]
1840 #[doc = #doc]
1841 }
1842 } else {
1843 quote! {
1844 #[doc = #doc]
1845 }
1846 }
1847 })
1848 .collect()
1849}
1850
1851fn generate_stateless_handler_code(handler: &CHandler) -> TokenStream {
1852 let type_name_ident = format_ident!("{}", handler.type_name);
1853 let callback_fn_name = format_ident!("{}_callback", handler.type_name);
1854 let closure_type_name = format_ident!("{}Callback", snake_to_pascal_case(&handler.type_name));
1855 let logger_type_name = format_ident!("{}Logger", snake_to_pascal_case(&handler.type_name));
1856 let handle_method_name = format_ident!("handle_{}", &handler.type_name[..handler.type_name.len() - 2]);
1857 let closure_return_type = handler.return_type.as_type();
1858
1859 let (fn_mut_args, trait_args): (Vec<TokenStream>, Vec<TokenStream>) = handler
1861 .args
1862 .iter()
1863 .enumerate()
1864 .map(|(i, arg)| {
1865 let return_type = ReturnType::new(arg.clone(), BTreeMap::new());
1866 let type_name = return_type.get_new_return_type(false, false);
1867 let arg_name = format_ident!("arg_{}", i);
1868
1869 let fn_mut_arg = if arg.is_single_mut_pointer() && arg.is_primitive() {
1870 let owned_type: Type = parse_str(arg.c_type.split_whitespace().last().unwrap()).unwrap();
1871 quote! { #owned_type }
1872 } else {
1873 quote! { #type_name }
1874 };
1875
1876 let trait_arg = if type_name.is_empty() {
1877 quote! {}
1878 } else if arg.is_single_mut_pointer() && arg.is_primitive() {
1879 let owned_type: Type = parse_str(arg.c_type.split_whitespace().last().unwrap()).unwrap();
1880 quote! { #arg_name: #owned_type }
1881 } else {
1882 quote! { #arg_name: #type_name }
1883 };
1884
1885 (fn_mut_arg, trait_arg)
1886 })
1887 .filter(|(fn_mut, trait_)| !fn_mut.is_empty() && !trait_.is_empty())
1888 .unzip();
1889
1890 let fn_mut_sig = quote! {
1892 FnMut(#(#fn_mut_args),*) -> #closure_return_type
1893 };
1894
1895 quote! {
1896 pub trait #closure_type_name {
1897 fn #handle_method_name(&mut self, #(#trait_args),*) -> #closure_return_type;
1898 }
1899
1900 pub struct #logger_type_name;
1901 impl #closure_type_name for #logger_type_name {
1902 fn #handle_method_name(&mut self, #(#trait_args),*) -> #closure_return_type {
1903 log::info!(
1904 "{}({}\n)",
1905 stringify!(#handle_method_name),
1906 ""
1907 );
1908 unimplemented!()
1909 }
1910 }
1911
1912 #[allow(dead_code)]
1914 unsafe extern "C" fn #callback_fn_name<F: #closure_type_name>(#(#trait_args),*) -> #closure_return_type {
1915 unimplemented!("Stateless handler callback called - not supported")
1916 }
1917 }
1918}
1919
1920pub fn generate_handlers(handler: &mut CHandler, bindings: &CBinding) -> TokenStream {
1921 if handler
1922 .args
1923 .iter()
1924 .any(|arg| arg.is_primitive() && arg.is_mut_pointer())
1925 {
1926 return quote! {};
1927 }
1928
1929 let has_c_void_param = handler.args.iter().any(|a| a.is_c_void());
1933 let is_stateless = !has_c_void_param;
1934
1935 if is_stateless {
1936 let closure_type_name = format_ident!("{}Callback", snake_to_pascal_case(&handler.type_name));
1937 let fn_mut_args: Vec<TokenStream> = handler
1939 .args
1940 .iter()
1941 .map(|arg| {
1942 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
1943 let type_name = return_type.get_new_return_type(false, false);
1944 if arg.is_single_mut_pointer() && arg.is_primitive() {
1945 let owned_type: Type = parse_str(arg.c_type.split_whitespace().last().unwrap()).unwrap();
1946 quote! { #owned_type }
1947 } else {
1948 quote! { #type_name }
1949 }
1950 })
1951 .filter(|t| !t.is_empty())
1952 .collect();
1953 let closure_return_type = handler.return_type.as_type();
1954 handler.fn_mut_signature = quote! {
1955 FnMut(#(#fn_mut_args),*) -> #closure_return_type
1956 };
1957 handler.closure_type_name = quote! {
1958 #closure_type_name
1959 };
1960 return generate_stateless_handler_code(handler);
1961 }
1962
1963 let fn_name = format_ident!("{}_callback", handler.type_name);
1964 let closure_fn_name = format_ident!("{}_callback_for_once_closure", handler.type_name);
1965 let doc_comments: Vec<TokenStream> = handler
1966 .docs
1967 .iter()
1968 .flat_map(|doc| doc.lines())
1969 .map(|line| quote! { #[doc = #line] })
1970 .collect();
1971
1972 let closure = handler
1973 .args
1974 .iter()
1975 .find(|a| a.is_c_void())
1976 .map(|a| a.name.clone())
1977 .unwrap_or_else(|| "state".to_string());
1978 let closure_name = format_ident!("{}", closure);
1979 let closure_type_name = format_ident!("{}Callback", snake_to_pascal_case(&handler.type_name));
1980 let closure_return_type = handler.return_type.as_type();
1981
1982 let logger_type_name = format_ident!("{}Logger", snake_to_pascal_case(&handler.type_name));
1983
1984 let handle_method_name = format_ident!("handle_{}", &handler.type_name[..handler.type_name.len() - 2]);
1985
1986 let no_method_name = format_ident!(
1987 "no_{}_handler",
1988 &handler.type_name[..handler.type_name.len() - 2]
1989 .replace("_on_", "_")
1990 .replace("aeron_", "")
1991 );
1992
1993 let args: Vec<TokenStream> = handler
1994 .args
1995 .iter()
1996 .map(|arg| {
1997 let arg_name = arg.as_ident();
1998 let arg_type: Type = arg.as_type();
2000 quote! { #arg_name: #arg_type }
2001 })
2002 .filter(|t| !t.is_empty())
2003 .collect();
2004
2005 let arg_names_for_logging: Vec<TokenStream> = handler
2006 .args
2007 .iter()
2008 .map(|arg| {
2009 let arg_name = arg.as_ident();
2010 quote! { format!("{} = {:?}", stringify!(#arg_name), #arg_name) }
2011 })
2012 .collect();
2013
2014 let converted_args: Vec<TokenStream> = handler
2015 .args
2016 .iter()
2017 .filter_map(|arg| {
2018 let name = &arg.name;
2019 let arg_name = arg.as_ident();
2020 if name == &closure {
2023 None
2024 } else {
2025 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
2026 Some(return_type.handle_c_to_rs_return(quote! {#arg_name}, false, false))
2027 }
2028 })
2029 .filter(|t| !t.is_empty())
2030 .collect();
2031
2032 let closure_args: Vec<TokenStream> = handler
2033 .args
2034 .iter()
2035 .filter_map(|arg| {
2036 let name = &arg.name;
2037 if name == &closure {
2038 return None;
2039 }
2040
2041 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
2042 let type_name = return_type.get_new_return_type(false, false);
2043 let field_name = format_ident!("{}", name);
2044 if type_name.is_empty() {
2045 None
2046 } else {
2047 Some(quote! {
2048 #field_name: #type_name
2049 })
2050 }
2051 })
2052 .filter(|t| !t.is_empty())
2053 .collect();
2054
2055 let mut log_field_names = vec![];
2056 let closure_args_in_logger: Vec<TokenStream> = handler
2057 .args
2058 .iter()
2059 .filter_map(|arg| {
2060 let name = &arg.name;
2061 if name == &closure {
2062 return None;
2063 }
2064
2065 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
2066 let type_name = return_type.get_new_return_type(false, false);
2067 let field_name = format_ident!("{}", name);
2068 if type_name.is_empty() {
2069 None
2070 } else {
2071 log_field_names.push(Some(
2072 quote! { format!("{} : {:?}", stringify!(#field_name), #field_name) },
2073 ));
2074
2075 Some(quote! {
2076 #field_name: #type_name
2077 })
2078 }
2079 })
2080 .filter(|t| !t.is_empty())
2081 .collect();
2082
2083 if log_field_names.is_empty() {
2084 log_field_names.push(Some(quote! { "" }));
2085 }
2086
2087 let fn_mut_args: Vec<TokenStream> = handler
2088 .args
2089 .iter()
2090 .filter_map(|arg| {
2091 let name = &arg.name;
2092 if name == &closure {
2093 return None;
2094 }
2095
2096 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
2097 let type_name = return_type.get_new_return_type(false, false);
2098 if arg.is_single_mut_pointer() && arg.is_primitive() {
2099 let owned_type: Type = parse_str(arg.c_type.split_whitespace().last().unwrap()).unwrap();
2100 return Some(quote! { #owned_type });
2101 } else {
2102 return Some(quote! {
2103 #type_name
2104 });
2105 }
2106 })
2107 .filter(|t| !t.is_empty())
2108 .collect();
2109
2110 handler.fn_mut_signature = quote! {
2111 FnMut(#(#fn_mut_args),*) -> #closure_return_type
2112 };
2113 handler.closure_type_name = quote! {
2114 #closure_type_name
2115 };
2116
2117 let logger_return_type = if closure_return_type.to_token_stream().to_string().eq("()") {
2118 closure_return_type.clone().to_token_stream()
2119 } else {
2120 quote! {
2121 unimplemented!()
2122 }
2123 };
2124
2125 let wrapper_closure_args: Vec<TokenStream> = handler
2126 .args
2127 .iter()
2128 .filter_map(|arg| {
2129 let name = &arg.name;
2130 if name == &closure {
2131 return None;
2132 }
2133
2134 let field_name = format_ident!("{}", name);
2135 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone()).get_new_return_type(false, false);
2136 if return_type.is_empty() {
2137 None
2138 } else {
2139 Some(quote! { #field_name })
2140 }
2141 })
2142 .filter(|t| !t.is_empty())
2143 .collect();
2144
2145 quote! {
2146 #(#doc_comments)*
2147 pub trait #closure_type_name {
2151 fn #handle_method_name(&mut self, #(#closure_args),*) -> #closure_return_type;
2152 }
2153
2154 pub struct #logger_type_name;
2155 impl #closure_type_name for #logger_type_name {
2156 fn #handle_method_name(&mut self, #(#closure_args_in_logger),*) -> #closure_return_type {
2157 log::info!("{}({}\n)",
2158 stringify!(#handle_method_name),
2159 [#(#log_field_names),*].join(", "),
2160 );
2161 #logger_return_type
2162 }
2163 }
2164
2165 unsafe impl Send for #logger_type_name {}
2166 unsafe impl Sync for #logger_type_name {}
2167
2168 impl Handlers {
2169 pub fn #no_method_name() -> Option<&'static Handler<#logger_type_name>> {
2171 None::<&Handler<#logger_type_name>>
2172 }
2173 }
2174
2175 #[allow(dead_code)]
2177 #(#doc_comments)*
2178 unsafe extern "C" fn #fn_name<F: #closure_type_name>(
2179 #(#args),*
2180 ) -> #closure_return_type
2181 {
2182 #[cfg(debug_assertions)]
2183 if #closure_name.is_null() {
2184 unimplemented!("closure should not be null")
2185 }
2186 #[cfg(feature = "extra-logging")]
2187 {
2188 log::debug!("calling {}", stringify!(#handle_method_name));
2189 }
2190 #[cfg(feature = "log-c-bindings")]
2191 log::debug!(
2192 "{}({}\n)",
2193 stringify!(#fn_name),
2194 [#(#arg_names_for_logging),*].join(", ")
2195 );
2196 let closure: &mut F = &mut *(#closure_name as *mut F);
2197 closure.#handle_method_name(#(#converted_args),*)
2198 }
2199
2200 #[allow(dead_code)]
2202 #(#doc_comments)*
2203 unsafe extern "C" fn #closure_fn_name<F: FnMut(#(#fn_mut_args),*) -> #closure_return_type>(
2204 #(#args),*
2205 ) -> #closure_return_type
2206 {
2207 #[cfg(debug_assertions)]
2208 if #closure_name.is_null() {
2209 unimplemented!("closure should not be null")
2210 }
2211 #[cfg(feature = "extra-logging")]
2212 {
2213 log::debug!("calling {}", stringify!(#closure_fn_name));
2214 }
2215 #[cfg(feature = "log-c-bindings")]
2216 log::debug!(
2217 "{}({}\n)",
2218 stringify!(#closure_fn_name),
2219 [#(#arg_names_for_logging),*].join(", ")
2220 );
2221 let closure: &mut F = &mut *(#closure_name as *mut F);
2222 closure(#(#converted_args),*)
2223 }
2224
2225 }
2226}
2227
2228pub fn generate_rust_code(
2229 wrapper: &CWrapper,
2230 wrappers: &BTreeMap<String, CWrapper>,
2231 include_common_code: bool,
2232 include_clippy: bool,
2233 include_aeron_client_registering_resource_t: bool,
2234 closure_handlers: &Vec<CHandler>,
2235) -> TokenStream {
2236 let class_name = Ident::new(&wrapper.class_name, proc_macro2::Span::call_site());
2237 let type_name = Ident::new(&wrapper.type_name, proc_macro2::Span::call_site());
2238
2239 let mut additional_outer_impls = vec![];
2240 let mut debug_fields = vec![];
2241
2242 let methods = wrapper.generate_methods(
2243 wrappers,
2244 closure_handlers,
2245 &mut additional_outer_impls,
2246 &mut debug_fields,
2247 );
2248 let tests = wrapper.generate_allocation_test();
2249 let mut constructor_fields = vec![];
2250 let mut new_ref_set_none = vec![];
2251 let constructor = wrapper.generate_constructor(wrappers, &mut constructor_fields, &mut new_ref_set_none);
2252
2253 let async_impls = if wrapper.type_name.starts_with("aeron_async_")
2254 || wrapper.type_name.starts_with("aeron_archive_async_")
2255 {
2256 let new_method = wrapper.methods.iter().find(|m| m.fn_name == wrapper.without_name);
2257
2258 if let Some(new_method) = new_method {
2259 let main_type = &wrapper.type_name.replace("_async_", "_").replace("_add_", "_");
2260 let main = get_possible_wrappers(main_type)
2261 .iter()
2262 .filter_map(|f| wrappers.get(f))
2263 .next()
2264 .expect(&format!("failed to find main type {}", main_type));
2265
2266 let poll_method = main
2267 .methods
2268 .iter()
2269 .find(|m| m.fn_name == format!("{}_poll", wrapper.without_name))
2270 .unwrap();
2271
2272 let main_class_name = format_ident!("{}", main.class_name);
2273 let async_class_name = format_ident!("{}", wrapper.class_name);
2274 let poll_method_name = format_ident!("{}_poll", wrapper.without_name);
2275 let new_method_name = format_ident!("{}", new_method.fn_name);
2276
2277 let client_class = wrappers
2278 .get(
2279 new_method
2280 .arguments
2281 .iter()
2282 .skip(1)
2283 .next()
2284 .unwrap()
2285 .c_type
2286 .split_whitespace()
2287 .last()
2288 .unwrap(),
2289 )
2290 .unwrap();
2291 let client_type = format_ident!("{}", client_class.class_name);
2292 let client_type_method_name = format_ident!(
2293 "{}",
2294 new_method
2295 .fn_name
2296 .replace(&format!("{}_", client_class.without_name), "")
2297 );
2298 let client_type_method_name_without_async = format_ident!(
2299 "{}",
2300 new_method
2301 .fn_name
2302 .replace(&format!("{}_", client_class.without_name), "")
2303 .replace("async_", "")
2304 );
2305
2306 let init_args: Vec<TokenStream> = poll_method
2307 .arguments
2308 .iter()
2309 .enumerate()
2310 .filter_map(|(idx, arg)| {
2311 if idx == 0 {
2312 Some(quote! { ctx_field })
2313 } else {
2314 let arg_name = arg.as_ident();
2315 let arg_name = ReturnType::new(arg.clone(), wrappers.clone())
2316 .handle_rs_to_c_return(quote! { #arg_name }, false);
2317 Some(quote! { #arg_name })
2318 }
2319 })
2320 .filter(|t| !t.is_empty())
2321 .collect();
2322
2323 let new_args: Vec<TokenStream> = poll_method
2324 .arguments
2325 .iter()
2326 .enumerate()
2327 .filter_map(|(idx, arg)| {
2328 if idx == 0 {
2329 None
2330 } else {
2331 let arg_name = arg.as_ident();
2332 let arg_type = ReturnType::new(arg.clone(), wrappers.clone()).get_new_return_type(false, true);
2333 if arg_type.clone().into_token_stream().is_empty() {
2334 None
2335 } else {
2336 Some(quote! { #arg_name: #arg_type })
2337 }
2338 }
2339 })
2340 .filter(|t| !t.is_empty())
2341 .collect();
2342
2343 let async_init_args: Vec<TokenStream> = new_method
2344 .arguments
2345 .iter()
2346 .enumerate()
2347 .filter_map(|(idx, arg)| {
2348 if idx == 0 {
2349 Some(quote! { ctx_field })
2350 } else {
2351 let arg_name = arg.as_ident();
2352 let arg_name = ReturnType::new(arg.clone(), wrappers.clone())
2353 .handle_rs_to_c_return(quote! { #arg_name }, false);
2354 Some(quote! { #arg_name })
2355 }
2356 })
2357 .filter(|t| !t.is_empty())
2358 .collect();
2359
2360 let async_log_expr_tokens = CWrapper::generate_arg_logging(&new_method.arguments, &async_init_args);
2362
2363 let generic_types: Vec<TokenStream> = new_method
2364 .arguments
2365 .iter()
2366 .flat_map(|arg| {
2367 ReturnType::new(arg.clone(), wrappers.clone())
2368 .method_generics_for_where()
2369 .into_iter()
2370 })
2371 .collect_vec();
2372 let where_clause_async = if generic_types.is_empty() {
2373 quote! {}
2374 } else {
2375 quote! { <#(#generic_types),*> }
2376 };
2377 let generic_types: Vec<TokenStream> = poll_method
2378 .arguments
2379 .iter()
2380 .flat_map(|arg| {
2381 ReturnType::new(arg.clone(), wrappers.clone())
2382 .method_generics_for_where()
2383 .into_iter()
2384 })
2385 .collect_vec();
2386 let where_clause_main = if generic_types.is_empty() {
2387 quote! {}
2388 } else {
2389 quote! { <#(#generic_types),*> }
2390 };
2391 let async_new_args: Vec<TokenStream> = new_method
2392 .arguments
2393 .iter()
2394 .enumerate()
2395 .filter_map(|(idx, arg)| {
2396 if idx == 0 {
2397 None
2398 } else {
2399 let arg_name = arg.as_ident();
2400 let arg_type = ReturnType::new(arg.clone(), wrappers.clone()).get_new_return_type(false, true);
2401 if arg_type.clone().into_token_stream().is_empty() {
2402 None
2403 } else {
2404 Some(quote! { #arg_name: #arg_type })
2405 }
2406 }
2407 })
2408 .filter(|t| !t.is_empty())
2409 .collect();
2410
2411 let async_dependancies = async_new_args
2412 .iter()
2413 .filter(|a| a.to_string().contains(" : Aeron") || a.to_string().contains(" : & Aeron"))
2414 .map(|e| {
2415 let var_name = format_ident!("{}", e.to_string().split_whitespace().next().unwrap());
2416 quote! {
2417 result.inner.add_dependency(#var_name.clone());
2418 }
2419 })
2420 .collect_vec();
2421
2422 let async_new_args_for_client = async_new_args.iter().skip(1).cloned().collect_vec();
2423
2424 let async_new_args_name_only: Vec<TokenStream> = new_method
2425 .arguments
2426 .iter()
2427 .enumerate()
2428 .filter_map(|(idx, arg)| {
2429 if idx < 2 {
2430 None
2431 } else {
2432 let arg_name = arg.as_ident();
2433 let arg_type = ReturnType::new(arg.clone(), wrappers.clone()).get_new_return_type(false, false);
2434 if arg_type.clone().into_token_stream().is_empty() {
2435 None
2436 } else {
2437 Some(quote! { #arg_name })
2438 }
2439 }
2440 })
2441 .filter(|t| !t.is_empty())
2442 .collect();
2443
2444 let poll_log_expr_tokens = CWrapper::generate_arg_logging(&poll_method.arguments, &init_args);
2446 let is_closed_method = main.get_is_closed_method_quote();
2447
2448 quote! {
2449 impl #main_class_name {
2450 #[inline]
2451 pub fn new #where_clause_main (#(#new_args),*) -> Result<Self, AeronCError> {
2452 let resource = ManagedCResource::new(
2453 move |ctx_field| unsafe {
2454 #[cfg(feature = "log-c-bindings")]
2455 {
2456 let log_args = #poll_log_expr_tokens;
2457 log::info!("{}({})", stringify!(#poll_method_name), log_args);
2458 }
2459 #poll_method_name(#(#init_args),*)
2460 },
2461 None,
2462 false,
2463 #is_closed_method,
2464 )?;
2465 Ok(Self {
2466 inner: CResource::OwnedOnHeap(std::rc::Rc::new(resource)),
2467 })
2468 }
2469 }
2470
2471 impl #client_type {
2472 #[inline]
2473 pub fn #client_type_method_name #where_clause_async(&self, #(#async_new_args_for_client),*) -> Result<#async_class_name, AeronCError> {
2474 let mut result = #async_class_name::new(self, #(#async_new_args_name_only),*);
2475 if let Ok(result) = &mut result {
2476 result.inner.add_dependency(self.clone());
2477 }
2478
2479 result
2480 }
2481 }
2482
2483 impl #client_type {
2484 #[inline]
2485 pub fn #client_type_method_name_without_async #where_clause_async(&self #(
2486 , #async_new_args_for_client)*, timeout: std::time::Duration) -> Result<#main_class_name, AeronCError> {
2487 let start = std::time::Instant::now();
2488 loop {
2489 if let Ok(poller) = #async_class_name::new(self, #(#async_new_args_name_only),*) {
2490 while start.elapsed() <= timeout {
2491 if let Some(result) = poller.poll()? {
2492 return Ok(result);
2493 }
2494 #[cfg(debug_assertions)]
2495 std::thread::sleep(std::time::Duration::from_millis(10));
2496 }
2497 }
2498 if start.elapsed() > timeout {
2499 log::error!("failed async poll for {:?}", self);
2500 return Err(AeronErrorType::TimedOut.into());
2501 }
2502 #[cfg(debug_assertions)]
2503 std::thread::sleep(std::time::Duration::from_millis(10));
2504 }
2505 }
2506 }
2507
2508 impl #async_class_name {
2509 #[inline]
2510 pub fn new #where_clause_async (#(#async_new_args),*) -> Result<Self, AeronCError> {
2511 let resource_async = ManagedCResource::new(
2512 move |ctx_field| unsafe {
2513 #[cfg(feature = "log-c-bindings")]
2514 {
2515 let log_args = #async_log_expr_tokens;
2516 log::info!("{}({})", stringify!(#new_method_name), log_args);
2517 }
2518 #new_method_name(#(#async_init_args),*)
2519 },
2520 None,
2521 false,
2522 None,
2523 )?;
2524 let result = Self {
2525 inner: CResource::OwnedOnHeap(std::rc::Rc::new(resource_async)),
2526 };
2527 #(#async_dependancies)*
2528 Ok(result)
2529 }
2530
2531 pub fn poll(&self) -> Result<Option<#main_class_name>, AeronCError> {
2532
2533 if let Some(inner) = self.inner.as_owned() {
2534 if inner.is_resource_released() {
2535 return Ok(None);
2536 }
2537 }
2538
2539 let mut result = #main_class_name::new(self);
2540 if let Ok(result) = &mut result {
2541 unsafe {
2542 for d in (&mut *self.inner.as_owned().unwrap().dependencies.get()).iter_mut() {
2543 result.inner.add_dependency(d.clone());
2544 }
2545 }
2546 }
2547
2548 match result {
2549 Ok(result) => {
2550 if let Some(inner) = self.inner.as_owned() {
2551 inner.mark_resource_released();
2552 }
2553 result.inner.as_owned().unwrap().auto_close.set(true);
2554 Ok(Some(result))
2555 }
2556 Err(AeronCError {code }) if code == 0 => {
2557 Ok(None) }
2559 Err(e) => {
2560 if let Some(inner) = self.inner.as_owned() {
2561 inner.mark_resource_released();
2562 }
2563 Err(e)
2564 }
2565 }
2566 }
2567
2568 pub fn poll_blocking(&self, timeout: std::time::Duration) -> Result<#main_class_name, AeronCError> {
2569 if let Some(result) = self.poll()? {
2570 return Ok(result);
2571 }
2572
2573 let time = std::time::Instant::now();
2574 while time.elapsed() < timeout {
2575 if let Some(result) = self.poll()? {
2576 return Ok(result);
2577 }
2578 #[cfg(debug_assertions)]
2579 std::thread::sleep(std::time::Duration::from_millis(10));
2580 }
2581 log::error!("failed async poll for {:?}", self);
2582 Err(AeronErrorType::TimedOut.into())
2583 }
2584 }
2585 }
2586 } else {
2587 quote! {}
2588 }
2589 } else {
2590 quote! {}
2591 };
2592
2593 let mut additional_impls = vec![];
2594
2595 if let Some(close_method) = wrapper.get_close_method() {
2596 if !wrapper.methods.iter().any(|m| m.fn_name.contains("_init")) {
2597 let close_method_call = if close_method.arguments.len() > 1 {
2598 let has_handler_callbacks = close_method
2600 .arguments
2601 .iter()
2602 .skip(1)
2603 .any(|arg| arg.name.contains("clientd") || arg.name.starts_with("on_"));
2604
2605 if has_handler_callbacks {
2606 additional_impls.push(quote! {
2608 impl #class_name {
2609 pub fn close_with_no_args(&self) -> Result<(), AeronCError> {
2610 self.close(Handlers::no_notification_handler())?;
2611 Ok(())
2612 }
2613 }
2614 });
2615
2616 let ident = format_ident!("close_with_no_args");
2617 quote! {#ident}
2618 } else {
2619 let close_method_args = close_method
2621 .arguments
2622 .iter()
2623 .skip(1)
2624 .map(|arg| {
2625 let arg_name = arg.as_ident();
2626 if arg.c_type == "()" {
2627 quote! {}
2628 } else {
2629 quote! { #arg_name }
2630 }
2631 })
2632 .collect::<Vec<_>>();
2633
2634 additional_impls.push(quote! {
2635 impl #class_name {
2636 pub fn close_with_no_args(&self) -> Result<(), AeronCError> {
2637 self.close(Handlers::no_notification_handler(), #(#close_method_args),*)?;
2638 Ok(())
2639 }
2640 }
2641 });
2642
2643 let ident = format_ident!("close_with_no_args");
2644 quote! {#ident}
2645 }
2646 } else {
2647 let ident = format_ident!("{}", close_method.struct_method_name);
2648 quote! {#ident}
2649 };
2650
2651 if wrapper.type_name == "aeron_counter_t" {
2653 additional_impls.push(quote! {
2654 impl #class_name {
2655 #[inline]
2656 pub fn addr_atomic(&self) -> &std::sync::atomic::AtomicI64 {
2657 unsafe { std::sync::atomic::AtomicI64::from_ptr(self.addr()) }
2658 }
2659 }
2660 });
2661 } else if wrapper.type_name == "aeron_publication_t" || wrapper.type_name == "aeron_exclusive_publication_t"
2662 {
2663 additional_impls.push(quote! {
2664 impl #class_name {
2665 #[inline]
2666 pub fn is_ready(&self) -> bool {
2667 self.is_connected() && self.position_limit() != 0
2668 }
2669 }
2670 });
2671 }
2672 let is_closed_method = if wrapper.get_is_closed_method().is_some() {
2673 quote! { self.is_closed() }
2674 } else {
2675 quote! { false }
2676 };
2677
2678 additional_impls.push(quote! {
2679 impl Drop for #class_name {
2680 fn drop(&mut self) {
2681 if let Some(inner) = self.inner.as_owned() {
2682 if (inner.cleanup.is_none() ) && std::rc::Rc::strong_count(inner) == 1 && !inner.is_closed_already_called() {
2683 if inner.auto_close.get() {
2684 log::info!("auto closing {self:?}");
2685 let result = self.#close_method_call();
2686 log::debug!("result {:?}", result);
2687 } else {
2688 #[cfg(feature = "extra-logging")]
2689 log::warn!("{} not closed", stringify!(#class_name));
2690 }
2691 }
2692 }
2693 }
2694 }
2695 });
2696 }
2697 }
2698
2699 let common_code = if !include_common_code {
2700 quote! {}
2701 } else {
2702 TokenStream::from_str(COMMON_CODE).unwrap()
2703 };
2704 let warning_code = if !include_common_code {
2705 quote! {}
2706 } else {
2707 let mut code = String::new();
2708
2709 if include_clippy {
2710 code.push_str(
2711 " #![allow(non_upper_case_globals)]
2712 #![allow(non_camel_case_types)]
2713 #![allow(non_snake_case)]
2714 #![allow(clippy::all)]
2715 #![allow(unused_variables)]
2716 #![allow(unused_unsafe)]
2717",
2718 );
2719 }
2720
2721 if include_aeron_client_registering_resource_t {
2722 code.push_str(
2723 "
2724 type aeron_client_registering_resource_t = aeron_client_registering_resource_stct;
2725",
2726 );
2727 }
2728
2729 TokenStream::from_str(code.as_str()).unwrap()
2730 };
2731 let class_docs: Vec<TokenStream> = wrapper
2732 .docs
2733 .iter()
2734 .map(|doc| {
2735 quote! {
2736 #[doc = #doc]
2737 }
2738 })
2739 .collect();
2740
2741 let fields = wrapper.generate_fields(&wrappers, &mut debug_fields);
2742
2743 let default_impl =
2744 if wrapper.has_default_method() && !constructor.iter().map(|x| x.to_string()).join("").trim().is_empty() {
2745 quote! {
2756 impl Default for #class_name {
2758 fn default() -> Self {
2759 #class_name::new_zeroed_on_heap()
2760 }
2761 }
2762
2763 impl #class_name {
2764 pub fn clone_struct(&self) -> Self {
2773 let copy = Self::default();
2774 copy.get_inner_mut().clone_from(self.deref());
2775 copy
2776 }
2777 }
2778 }
2779 } else {
2780 quote! {}
2781 };
2782
2783 let is_closed_method = wrapper.get_is_closed_method_quote();
2784
2785 quote! {
2786 #warning_code
2787
2788 #(#class_docs)*
2789 #[derive(Clone)]
2790 pub struct #class_name {
2791 inner: CResource<#type_name>,
2792 #(#constructor_fields)*
2793 }
2794
2795 impl core::fmt::Debug for #class_name {
2796 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2797 if self.inner.get().is_null() {
2798 f.debug_struct(stringify!(#class_name))
2799 .field("inner", &"null")
2800 .finish()
2801 } else {
2802 f.debug_struct(stringify!(#class_name))
2803 .field("inner", &self.inner)
2804 #(#debug_fields)*
2805 .finish()
2806 }
2807 }
2808 }
2809
2810 impl #class_name {
2811 #(#constructor)*
2812 #(#fields)*
2813 #(#methods)*
2814
2815 #[inline(always)]
2816 pub fn get_inner(&self) -> *mut #type_name {
2817 self.inner.get()
2818 }
2819
2820 #[inline(always)]
2821 pub fn get_inner_mut(&self) -> &mut #type_name {
2822 unsafe { &mut *self.inner.get() }
2823 }
2824
2825 #[inline(always)]
2826 pub fn get_inner_ref(&self) -> & #type_name {
2827 unsafe { &*self.inner.get() }
2828 }
2829 }
2830
2831 impl std::ops::Deref for #class_name {
2832 type Target = #type_name;
2833
2834 fn deref(&self) -> &Self::Target {
2835 self.get_inner_ref()
2836 }
2837 }
2838
2839 impl From<*mut #type_name> for #class_name {
2840 #[inline]
2841 fn from(value: *mut #type_name) -> Self {
2842 #class_name {
2843 inner: CResource::Borrowed(value),
2844 #(#new_ref_set_none)*
2845 }
2846 }
2847 }
2848
2849 impl From<#class_name> for *mut #type_name {
2850 #[inline]
2851 fn from(value: #class_name) -> Self {
2852 value.get_inner()
2853 }
2854 }
2855
2856 impl From<&#class_name> for *mut #type_name {
2857 #[inline]
2858 fn from(value: &#class_name) -> Self {
2859 value.get_inner()
2860 }
2861 }
2862
2863 impl From<#class_name> for #type_name {
2864 #[inline]
2865 fn from(value: #class_name) -> Self {
2866 unsafe { *value.get_inner().clone() }
2867 }
2868 }
2869
2870 impl From<*const #type_name> for #class_name {
2871 #[inline]
2872 fn from(value: *const #type_name) -> Self {
2873 #class_name {
2874 inner: CResource::Borrowed(value as *mut #type_name),
2875 #(#new_ref_set_none)*
2876 }
2877 }
2878 }
2879
2880 impl From<#type_name> for #class_name {
2881 #[inline]
2882 fn from(value: #type_name) -> Self {
2883 #class_name {
2884 inner: CResource::OwnedOnStack(MaybeUninit::new(value)),
2885 #(#new_ref_set_none)*
2886 }
2887 }
2888 }
2889
2890 #(#additional_impls)*
2891
2892 #async_impls
2893 #default_impl
2894 #tests
2895 #common_code
2896 }
2897}