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