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