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