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