rusteron_code_gen/
generator.rs

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