Skip to main content

rusteron_code_gen/
generator.rs

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