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