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