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