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