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
41const SYNC_HANDLER_TYPES: &[&str] = &[
47 "aeron_fragment_handler_t",
48 "aeron_controlled_fragment_handler_t",
49 "aeron_block_handler_t",
50 "aeron_error_log_reader_func_t",
51 "aeron_loss_reporter_read_entry_func_t",
52 "aeron_uri_parse_callback_t",
53 "aeron_reserved_value_supplier_t",
54 "aeron_counters_reader_foreach_counter_func_t",
55 "aeron_counters_reader_foreach_metadata_func_t",
56 "aeron_str_to_ptr_hash_map_for_each_func_t",
57 "aeron_rb_handler_t",
58 "aeron_rb_controlled_handler_t",
59 "aeron_queue_drain_func_t",
60 "aeron_term_gap_scanner_on_gap_detected_func_t",
61 "aeron_archive_recording_descriptor_consumer_func_t",
62 "aeron_archive_recording_subscription_descriptor_consumer_func_t",
63];
64
65pub fn is_sync_handler_type(c_type: &str) -> bool {
66 SYNC_HANDLER_TYPES.iter().any(|t| c_type.contains(t))
67}
68
69#[derive(Debug, Clone, Eq, PartialEq)]
70pub struct Arg {
71 pub name: String,
72 pub c_type: String,
73 pub processing: ArgProcessing,
74}
75
76impl Arg {
77 pub fn is_primitive(&self) -> bool {
78 static PRIMITIVE_TYPES: &[&str] = &[
79 "i64", "u64", "f32", "f64", "i32", "i16", "u32", "u16", "bool", "usize", "isize", "c_int",
80 ];
81 PRIMITIVE_TYPES.iter().any(|&f| self.c_type.ends_with(f))
82 }
83}
84
85impl Arg {
86 const C_INT_RETURN_TYPE_STR: &'static str = ":: std :: os :: raw :: c_int";
87 const C_CHAR_STR: &'static str = "* const :: std :: os :: raw :: c_char";
88 const C_MUT_CHAR_STR: &'static str = "* mut :: std :: os :: raw :: c_char";
89 const C_BYTE_ARRAY: &'static str = "* const u8";
90 const C_BYTE_MUT_ARRAY: &'static str = "* mut u8";
91 const STAR_MUT: &'static str = "* mut";
92 const DOUBLE_STAR_MUT: &'static str = "* mut * mut";
93 const C_VOID: &'static str = "* mut :: std :: os :: raw :: c_void";
94
95 pub fn is_any_pointer(&self) -> bool {
96 self.c_type.starts_with("* const") || self.c_type.starts_with("* mut")
97 }
98
99 pub fn is_c_string(&self) -> bool {
100 self.c_type == Self::C_CHAR_STR
101 }
102
103 pub fn is_c_string_any(&self) -> bool {
104 self.is_c_string() || self.is_mut_c_string()
105 }
106
107 pub fn is_mut_c_string(&self) -> bool {
108 self.c_type == Self::C_MUT_CHAR_STR
109 }
110
111 pub fn is_usize(&self) -> bool {
112 self.c_type == "usize"
113 }
114
115 pub fn is_byte_array(&self) -> bool {
116 self.c_type == Self::C_BYTE_ARRAY || self.c_type == Self::C_BYTE_MUT_ARRAY
117 }
118
119 pub fn is_mut_byte_array(&self) -> bool {
120 self.c_type == Self::C_BYTE_MUT_ARRAY
121 }
122
123 pub fn is_c_raw_int(&self) -> bool {
124 self.c_type == Self::C_INT_RETURN_TYPE_STR
125 }
126
127 pub fn is_mut_pointer(&self) -> bool {
128 self.c_type.starts_with(Self::STAR_MUT)
129 }
130
131 pub fn is_double_mut_pointer(&self) -> bool {
132 self.c_type.starts_with(Self::DOUBLE_STAR_MUT)
133 }
134
135 pub fn is_single_mut_pointer(&self) -> bool {
136 self.is_mut_pointer() && !self.is_double_mut_pointer()
137 }
138
139 pub fn is_c_void(&self) -> bool {
140 self.c_type == Self::C_VOID
141 }
142}
143
144impl Deref for Arg {
145 type Target = str;
146
147 fn deref(&self) -> &Self::Target {
148 &self.c_type
149 }
150}
151
152impl Arg {
153 pub fn as_ident(&self) -> Ident {
154 Ident::new(&self.name, proc_macro2::Span::call_site())
155 }
156
157 pub fn as_type(&self) -> Type {
158 parse_str(&self.c_type).expect("Invalid argument type")
159 }
160}
161
162#[derive(Debug, Clone)]
163pub struct CHandler {
164 pub type_name: String,
165 pub args: Vec<Arg>,
166 pub return_type: Arg,
167 pub docs: BTreeSet<String>,
168 pub fn_mut_signature: TokenStream,
169 pub closure_type_name: TokenStream,
170}
171
172#[derive(Debug, Clone)]
173pub struct ReturnType {
174 original: Arg,
175 wrappers: BTreeMap<String, CWrapper>,
176}
177
178impl ReturnType {
179 pub fn new(original_c_type: Arg, wrappers: BTreeMap<String, CWrapper>) -> Self {
180 ReturnType {
181 original: original_c_type,
182 wrappers,
183 }
184 }
185
186 pub fn get_new_return_type(&self, convert_errors: bool, use_ref_for_cwrapper: bool) -> TokenStream {
187 if let ArgProcessing::Handler(_) = self.original.processing {
188 if self.original.name.len() > 0 {
189 if !self.original.is_mut_pointer() {
190 let new_type =
191 parse_str::<Type>(&format!("{}HandlerImpl", snake_to_pascal_case(&self.original.c_type)))
192 .expect("Invalid class name in wrapper");
193 return quote! { Option<&Handler<#new_type>> };
194 } else {
195 return quote! {};
196 }
197 }
198 } else if let ArgProcessing::StringWithLength(_) = self.original.processing {
199 if self.original.name.len() > 0 {
200 if self.original.is_c_string() {
201 return quote! { &str };
202 } else if self.original.is_mut_c_string() {
203 if use_ref_for_cwrapper {
205 return quote! { &mut [u8] };
206 } else {
207 return quote! { &str };
208 }
209 } else {
210 return quote! {};
211 }
212 }
213 } else if let ArgProcessing::ByteArrayWithLength(_) = self.original.processing {
214 if self.original.name.len() > 0 {
215 if self.original.is_byte_array() {
216 if self.original.is_mut_byte_array() {
217 return quote! { &mut [u8] };
218 } else {
219 return quote! { &[u8] };
220 }
221 } else {
222 return quote! {};
223 }
224 }
225 }
226
227 if self.original.is_single_mut_pointer() {
228 let type_name = self.original.split(" ").last().unwrap();
229 if let Some(wrapper) = self.wrappers.get(type_name) {
230 let new_type = parse_str::<Type>(&wrapper.class_name).expect("Invalid class name in wrapper");
231 if use_ref_for_cwrapper {
232 return quote! { &#new_type };
233 } else {
234 return quote! { #new_type };
235 }
236 }
237 }
238 if let Some(wrapper) = self.wrappers.get(&self.original.c_type) {
239 let new_type = parse_str::<Type>(&wrapper.class_name).expect("Invalid class name in wrapper");
240 return quote! { #new_type };
241 }
242 if convert_errors && self.original.is_c_raw_int() {
243 return quote! { Result<i32, AeronCError> };
244 }
245 if self.original.is_c_string() {
246 if !convert_errors && use_ref_for_cwrapper {
248 return quote! { &std::ffi::CStr };
249 } else {
250 return quote! { &str };
251 }
252 }
253 let return_type: Type = parse_str(&self.original).expect("Invalid return type");
254 if self.original.is_single_mut_pointer() && self.original.is_primitive() {
255 let mut_type: Type =
256 parse_str(&return_type.to_token_stream().to_string().replace("* mut ", "&mut ")).unwrap();
257 return quote! { #mut_type };
258 }
259 quote! { #return_type }
260 }
261
262 pub fn handle_c_to_rs_return(&self, result: TokenStream, convert_errors: bool, use_self: bool) -> TokenStream {
263 if let ArgProcessing::StringWithLength(args) = &self.original.processing {
264 if !self.original.is_c_string_any() {
265 return quote! {};
266 }
267 let string_ptr = &args[0].as_ident();
269 let length = &args[1].as_ident();
270 let me = if use_self {
271 quote! {self.}
272 } else {
273 quote! {}
274 };
275 return quote! {
276 if #me #string_ptr.is_null() { "" } else { unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(#me #string_ptr as *const u8, #me #length.try_into().unwrap())) } }
277 };
278 }
279 if let ArgProcessing::ByteArrayWithLength(args) = &self.original.processing {
280 if !self.original.is_byte_array() {
281 return quote! {};
282 } else {
283 let star_const = &args[0].as_ident();
284 let length = &args[1].as_ident();
285 let me = if use_self {
286 quote! {self.}
287 } else {
288 quote! {}
289 };
290 if self.original.is_mut_byte_array() {
291 return quote! {
292 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()) } }
293 };
294 } else {
295 return quote! {
296 if #me #star_const.is_null() { &[] as &[_] } else { std::slice::from_raw_parts(#me #star_const, #me #length.try_into().unwrap()) }
297 };
298 }
299 }
300 }
301
302 if convert_errors && self.original.is_c_raw_int() {
303 quote! {
304 if result < 0 {
305 return Err(AeronCError::from_code(result));
306 } else {
307 return Ok(result)
308 }
309 }
310 } else if self.original.is_c_string() {
311 if let ArgProcessing::StringWithLength(args) = &self.original.processing {
312 let length = &args[1].as_ident();
313 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()))}};
314 } else {
315 return quote! { if #result.is_null() { ""} else { unsafe { std::ffi::CStr::from_ptr(#result).to_str().unwrap_or("") } } };
316 }
317 } else if self.original.is_single_mut_pointer() && self.original.is_primitive() {
318 return quote! {
319 unsafe { &mut *#result }
320 };
321 } else {
322 quote! { #result.into() }
323 }
324 }
325
326 pub fn method_generics_for_where(&self, force_static: bool) -> Option<TokenStream> {
333 if let ArgProcessing::Handler(handler_client) = &self.original.processing {
334 if !self.original.is_mut_pointer() {
335 let handler = handler_client.get(0).unwrap();
336 let new_type = parse_str::<Type>(&format!("{}HandlerImpl", snake_to_pascal_case(&handler.c_type)))
337 .expect("Invalid class name in wrapper");
338 let new_handler = parse_str::<Type>(&format!("{}Callback", snake_to_pascal_case(&handler.c_type)))
339 .expect("Invalid class name in wrapper");
340 let needs_static = force_static || !is_sync_handler_type(&handler.c_type);
341 return if needs_static {
342 Some(quote! {
343 #new_type: #new_handler + 'static
344 })
345 } else {
346 Some(quote! {
347 #new_type: #new_handler
348 })
349 };
350 }
351 }
352 None
353 }
354
355 pub fn method_generics_for_method(&self) -> Option<TokenStream> {
356 if let ArgProcessing::Handler(handler_client) = &self.original.processing {
357 if !self.original.is_mut_pointer() {
358 let handler = handler_client.get(0).unwrap();
359 let new_type = parse_str::<Type>(&format!("{}HandlerImpl", snake_to_pascal_case(&handler.c_type)))
360 .expect("Invalid class name in wrapper");
361 return Some(quote! {
362 #new_type
363 });
364 }
365 }
366 None
367 }
368
369 pub fn handle_rs_to_c_return(&self, result: TokenStream, include_field_name: bool) -> TokenStream {
370 if let ArgProcessing::Handler(handler_client) = &self.original.processing {
371 if !self.original.is_mut_pointer() {
372 let handler = handler_client.get(0).unwrap();
373 let handler_name = handler.as_ident();
374 let handler_type = handler.as_type();
375 let clientd_name = handler_client.get(1).unwrap().as_ident();
376 let method_name = format_ident!("{}_callback", handler.c_type);
377 let new_type =
378 parse_str::<Type>(&format!("{}HandlerImpl", snake_to_pascal_case(&self.original.c_type)))
379 .expect("Invalid class name in wrapper");
380 if include_field_name {
381 return quote! {
382 #handler_name: { let callback: #handler_type = if #handler_name.is_none() { None } else { Some(#method_name::<#new_type>) }; callback },
383 #clientd_name: #handler_name.map(|m|m.as_raw()).unwrap_or_else(|| std::ptr::null_mut())
384 };
385 } else {
386 return quote! {
387 { let callback: #handler_type = if #handler_name.is_none() { None } else { Some(#method_name::<#new_type>) }; callback },
388 #handler_name.map(|m|m.as_raw()).unwrap_or_else(|| std::ptr::null_mut())
389 };
390 }
391 } else {
392 return quote! {};
393 }
394 }
395 if let ArgProcessing::StringWithLength(handler_client) = &self.original.processing {
396 if !self.original.is_c_string_any() {
398 let array = handler_client.get(0).unwrap();
399 let array_name = array.as_ident();
400 let length_name = handler_client.get(1).unwrap().as_ident();
401 let ptr = if array.is_mut_c_string() {
403 quote! { #array_name.as_mut_ptr() as *mut _ }
404 } else {
405 quote! { #array_name.as_ptr() as *const _ }
406 };
407 if include_field_name {
408 return quote! {
409 #array_name: #ptr,
410 #length_name: #array_name.len()
411 };
412 } else {
413 return quote! {
414 #ptr,
415 #array_name.len()
416 };
417 }
418 } else {
419 return quote! {};
420 }
421 }
422 if let ArgProcessing::ByteArrayWithLength(handler_client) = &self.original.processing {
423 if !self.original.is_byte_array() {
424 let array = handler_client.get(0).unwrap();
425 let array_name = array.as_ident();
426 let length_name = handler_client.get(1).unwrap().as_ident();
427 if include_field_name {
428 return quote! {
429 #array_name: #array_name.as_ptr() as *mut _,
430 #length_name: #array_name.len()
431 };
432 } else {
433 return quote! {
434 #array_name.as_ptr() as *mut _,
435 #array_name.len()
436 };
437 }
438 } else {
439 return quote! {};
440 }
441 }
442
443 if include_field_name {
444 let arg_name = self.original.as_ident();
445 return if self.original.is_c_string() {
446 quote! {
447 #arg_name: #result.as_ptr()
448 }
449 } else {
450 if self.original.is_single_mut_pointer() && self.original.is_primitive() {
451 return quote! {
452 #arg_name: #result as *mut _
453 };
454 }
455
456 quote! { #arg_name: #result.into() }
457 };
458 }
459
460 if self.original.is_single_mut_pointer() && self.original.is_primitive() {
461 return quote! {
462 #result as *mut _
463 };
464 }
465
466 if self.original.is_c_string() {
467 quote! {
468 #result.as_ptr()
469 }
470 } else {
471 quote! { #result.into() }
472 }
473 }
474}
475
476#[derive(Debug, Clone, Default, Eq, PartialEq)]
477pub struct CWrapper {
478 pub class_name: String,
479 pub type_name: String,
480 pub without_name: String,
481 pub fields: Vec<Arg>,
482 pub methods: Vec<Method>,
483 pub docs: BTreeSet<String>,
484 pub skipped_methods: BTreeSet<String>,
487}
488
489pub fn parse_custom_methods(src: &str) -> HashMap<String, BTreeSet<String>> {
493 let mut result: HashMap<String, BTreeSet<String>> = HashMap::new();
494 let file = syn::parse_file(src).unwrap_or_else(|e| {
495 panic!(
496 "rusteron codegen: failed to parse aeron_custom.rs while extracting custom method \
497 names (this would silently empty the generator skip-list and emit duplicate \
498 methods): {e}"
499 )
500 });
501 for item in &file.items {
502 if let Item::Impl(impl_block) = item {
503 if impl_block.trait_.is_some() {
505 continue;
506 }
507 let type_name = impl_block.self_ty.to_token_stream().to_string();
508 let type_name = type_name.trim().to_string();
509 let entry = result.entry(type_name).or_default();
510 for impl_item in &impl_block.items {
511 if let ImplItem::Fn(method) = impl_item {
512 entry.insert(method.sig.ident.to_string());
513 }
514 }
515 }
516 }
517 result
518}
519
520impl CWrapper {
521 pub fn find_methods(&self, name: &str) -> Vec<Method> {
522 self.methods
523 .iter()
524 .filter(|m| m.struct_method_name == name)
525 .cloned()
526 .collect_vec()
527 }
528
529 pub fn find_unique_method(&self, name: &str) -> Option<Method> {
530 let results = self.find_methods(name);
531 if results.len() == 1 {
532 results.into_iter().next()
533 } else {
534 None
535 }
536 }
537
538 fn get_close_method(&self) -> Option<Method> {
539 self.find_unique_method("close")
540 }
541
542 fn generate_arg_logging(arguments: &[Arg], arg_names: &[TokenStream]) -> TokenStream {
544 let mut arg_names_idx = 0;
545 let mut arg_names_for_logging = vec![];
546
547 for (arg_idx, arg) in arguments.iter().enumerate() {
548 if arg_names_idx >= arg_names.len() {
549 break;
550 }
551
552 let arg_name_str = &arg.name;
553 let arg_type = arg.as_type();
554 let arg_ident = arg.as_ident();
555
556 match &arg.processing {
558 ArgProcessing::Handler(_) if !arg.is_mut_pointer() => {
559 arg_names_for_logging.push(quote! {
561 concat!(#arg_name_str, ": ", stringify!(#arg_type)).to_string()
562 });
563 arg_names_idx += 2; }
565 ArgProcessing::StringWithLength(_args) => {
566 if arg_idx > 0 && arguments[arg_idx - 1].processing == arg.processing {
568 continue;
569 }
570 arg_names_for_logging.push(quote! {
572 format!("{} = {:?}", #arg_name_str, #arg_ident)
573 });
574 arg_names_idx += 2;
575 }
576 ArgProcessing::ByteArrayWithLength(_args) => {
577 if arg_idx > 0 && arguments[arg_idx - 1].processing == arg.processing {
579 continue;
580 }
581 arg_names_for_logging.push(quote! {
583 format!("{}: {} (len={})", #arg_name_str, stringify!(#arg_type), #arg_ident.len())
584 });
585 arg_names_idx += 2;
586 }
587 _ => {
588 if arg.is_primitive() && !arg.is_any_pointer() {
590 arg_names_for_logging.push(quote! {
591 format!("{} = {:?}", #arg_name_str, #arg_ident)
592 });
593 } else {
594 arg_names_for_logging.push(quote! {
595 concat!(#arg_name_str, ": ", stringify!(#arg_type)).to_string()
596 });
597 }
598 arg_names_idx += 1;
599 }
600 }
601 }
602
603 if arg_names_for_logging.is_empty() {
605 quote! { [""; 0].join(", ") }
606 } else {
607 quote! { [#(#arg_names_for_logging),*].join(", ") }
608 }
609 }
610
611 fn generate_methods(
613 &self,
614 wrappers: &BTreeMap<String, CWrapper>,
615 closure_handlers: &Vec<CHandler>,
616 additional_outer_impls: &mut Vec<TokenStream>,
617 debug_fields: &mut Vec<TokenStream>,
618 ) -> Vec<TokenStream> {
619 self.methods
620 .iter()
621 .filter(|m| !m.arguments.iter().any(|arg| arg.is_double_mut_pointer()))
622 .filter(|m| !self.skipped_methods.contains(&m.struct_method_name))
623 .filter(|m| m.struct_method_name != "close")
624 .map(|method| {
625
626 let fn_name =
627 Ident::new(&method.struct_method_name, proc_macro2::Span::call_site());
628 let return_type_helper =
629 ReturnType::new(method.return_type.clone(), wrappers.clone());
630 let mut return_type = return_type_helper.get_new_return_type(true, false);
631 let ffi_call = Ident::new(&method.fn_name, proc_macro2::Span::call_site());
632
633 let classified = crate::arg_classifier::classify_method_args(method, &self.type_name, wrappers, closure_handlers);
637 let uses_self = classified.uses_self;
638 let owned_retained_handler = classified.owned_retained.clone();
639
640 let generic_types: Vec<TokenStream> = classified.generics();
641 let where_clause = if generic_types.is_empty() {
642 quote! {}
643 } else {
644 quote! { <#(#generic_types),*> }
645 };
646
647 let fn_arguments: Vec<TokenStream> = classified.signatures();
648 let mut arg_names: Vec<TokenStream> = classified.calls();
649 let retained_handler_registrations: Vec<TokenStream> = classified.registrations();
650
651 let mut converter = return_type_helper.handle_c_to_rs_return(quote! { result }, true, false);
652
653 let handler_prelude = if let Some(arg) = &owned_retained_handler {
656 let name = arg.as_ident();
657 let raw_name = format_ident!("{}_raw", arg.name);
658 quote! {
659 let #name = #name.map(Handler::new);
660 let #raw_name = #name
661 .as_ref()
662 .map(|m| m.as_raw())
663 .unwrap_or_else(|| std::ptr::null_mut());
664 }
665 } else {
666 quote! {}
667 };
668
669 if let Some(arg) = &owned_retained_handler {
670 let name = arg.as_ident();
671 let new_type = parse_str::<Type>(&format!(
672 "{}HandlerImpl",
673 snake_to_pascal_case(&arg.c_type)
674 ))
675 .expect("Invalid class name in wrapper");
676 return_type = quote! { Result<Option<Handler<#new_type>>, AeronCError> };
677 converter = quote! {
678 if result < 0 {
679 return Err(AeronCError::from_code(result));
680 } else {
681 return Ok(#name);
682 }
683 };
684 }
685
686 let mut method_docs: Vec<TokenStream> = get_docs(&method.docs, wrappers, Some(&fn_arguments) );
687
688 if owned_retained_handler.is_some() {
689 method_docs.push(quote! { #[doc = ""] });
690 method_docs.push(quote! { #[doc = " The callback is retained by the C client; this resource keeps it alive automatically."] });
691 method_docs.push(quote! { #[doc = " Returns the created [`Handler`] for optional state access — safe to ignore. Closures with a matching signature are accepted directly."] });
692 }
693
694 let args_log_expr = Self::generate_arg_logging(&method.arguments, &arg_names);
696
697 if uses_self && method.return_type.is_c_string_any() && method.arguments.len() == 1 {
698 let name = format_ident!("{}", method.struct_method_name);
699 debug_fields.push( quote! {
700 .field(stringify!(#name), &self.#name() )
701 } );
702 }
703
704 let possible_self = if uses_self {
705 quote! { &self, }
706 } else {
707 if return_type.to_string().eq("& str") {
708 return_type = quote! { &'static str };
709 method_docs.push(quote! {#[doc = "SAFETY: this is static for performance reasons, so you should not store this without copying it!!"]});
710 }
711 quote! {}
712 };
713
714
715
716 let register_handlers = if uses_self && !retained_handler_registrations.is_empty() {
717 quote! { #(#retained_handler_registrations)* }
718 } else {
719 quote! {}
720 };
721
722 let mut additional_methods = vec![];
723 let set_closed = quote! {};
724
725 Self::add_mut_string_methods_if_applicable(method, &fn_name, uses_self, &method_docs, &mut additional_methods);
726
727 Self::add_getter_instead_of_mut_arg_if_applicable(wrappers, method, &fn_name, &where_clause, &possible_self, &method_docs, &mut additional_methods, debug_fields);
729
730 if classified.once_capable
735 && !self
736 .skipped_methods
737 .contains(&format!("{}_fn", method.struct_method_name))
738 {
739 let once_fn_name = format_ident!("{}_fn", fn_name);
740 let once_generics = classified.once_generics();
741 let once_where = if once_generics.is_empty() {
742 quote! {}
743 } else {
744 quote! { <#(#once_generics),*> }
745 };
746 let once_args = classified.once_signatures();
747 let once_calls = classified.once_calls();
748 let once_log_expr = Self::generate_arg_logging(&method.arguments, &once_calls);
749 additional_methods.push(quote! {
750 #[inline]
751 #(#method_docs)*
752 pub fn #once_fn_name #once_where(#possible_self #(#once_args),*) -> #return_type {
767 #set_closed
768 unsafe {
769 #[cfg(feature = "log-c-bindings")]
770 log::info!(
771 "{}({})",
772 stringify!(#ffi_call),
773 #once_log_expr
774 );
775
776 let result = #ffi_call(#(#once_calls),*);
777
778 #[cfg(feature = "log-c-bindings")]
779 log::info!(" -> {:?}", result);
780
781 #converter
782 }
783 }
784 });
785 }
786
787 let mut_primitivies = method.arguments.iter()
788 .filter(|a| a.is_mut_pointer() && a.is_primitive())
789 .collect_vec();
790 let single_mut_field = method.return_type.is_c_raw_int() && mut_primitivies.len() == 1;
791
792 let __method_tokens = if single_mut_field {
795 let mut_field = mut_primitivies.first().unwrap();
796 let rt: Type = parse_str(mut_field.c_type.trim_start_matches("* mut").trim()).unwrap();
798 let return_type = quote! { Result<#rt, AeronCError> };
799
800 let fn_arguments= fn_arguments.into_iter().filter(|arg| {!arg.to_string().contains("& mut ")})
801 .collect_vec();
802
803 let idx = arg_names.iter().enumerate()
804 .filter(|(_, arg)| arg.to_string().ends_with("* mut _"))
805 .map(|(i, _)| i)
806 .next().unwrap();
807
808 arg_names[idx] = quote! { &mut mut_result };
809
810 let mut first = true;
811 let mut method_docs = method_docs.iter()
812 .filter(|d| !d.to_string().contains("# Return"))
813 .map(|d| {
814 let mut string = d.to_string();
815 string = string.replace("# Parameters", "");
816 if string.contains("out param") {
817 TokenStream::from_str(&string.replace("- `", "\n# Return\n`")).unwrap()
818 } else {
819 if string.contains("- `") && first {
820 first = false;
821 string = string.replacen("- `","# Parameters\n- `", 1);
822 }
823 TokenStream::from_str(&string).unwrap()
824 }
825 })
826 .collect_vec();
827
828 let filter_param_title = !method_docs.iter().any(|d| d.to_string().contains("- `"));
829
830 if filter_param_title {
831 method_docs = method_docs.into_iter()
832 .map(|s| TokenStream::from_str(s.to_string().replace("# Parameters\n", "").as_str()).unwrap())
833 .collect_vec();
834 }
835
836
837 quote! {
838 #[inline]
839 #(#method_docs)*
840 pub fn #fn_name #where_clause(#possible_self #(#fn_arguments),*) -> #return_type {
841 #set_closed
842 unsafe {
843 let mut mut_result: #rt = Default::default();
844
845 #[cfg(feature = "log-c-bindings")]
846 log::info!(
847 "{}({})",
848 stringify!(#ffi_call),
849 #args_log_expr
850 );
851
852 let err_code = #ffi_call(#(#arg_names),*);
853 #register_handlers
854
855 #[cfg(feature = "log-c-bindings")]
856 log::info!(" -> err_code = {:?}, result = {:?}", err_code, mut_result);
857
858 if err_code < 0 {
859 return Err(AeronCError::from_code(err_code));
860 } else {
861 return Ok(mut_result);
862 }
863 }
864 }
865
866 #(#additional_methods)*
867 }
868 } else {
869 quote! {
870 #[inline]
871 #(#method_docs)*
872 pub fn #fn_name #where_clause(#possible_self #(#fn_arguments),*) -> #return_type {
873 #set_closed
874 #handler_prelude
875 unsafe {
876 #[cfg(feature = "log-c-bindings")]
877 log::info!(
878 "{}({})",
879 stringify!(#ffi_call),
880 #args_log_expr
881 );
882
883 let result = #ffi_call(#(#arg_names),*);
884 #register_handlers
885
886 #[cfg(feature = "log-c-bindings")]
887 log::info!(" -> {:?}", result);
888
889 #converter
890 }
891 }
892
893 #(#additional_methods)*
894 }
895 };
896
897 if self.type_name == "aeron_archive_t" {
903 __method_tokens
904 .to_string()
905 .replace("AeronCError", "AeronArchiveError")
906 .parse()
907 .expect("AeronArchiveError token substitution must yield valid tokens")
908 } else {
909 __method_tokens
910 }
911 })
912 .collect()
913 }
914
915 fn handler_dependency_registrations(arguments: &[Arg]) -> Vec<TokenStream> {
919 arguments
920 .iter()
921 .filter_map(|arg| {
922 if let ArgProcessing::Handler(_) = &arg.processing {
923 if !arg.is_mut_pointer() {
924 let name = arg.as_ident();
925 return Some(quote! {
926 if let Some(__handler) = #name {
927 if let Some(__inner) = result.inner.as_owned() {
928 __inner.add_dependency(__handler.clone());
929 }
930 }
931 });
932 }
933 }
934 None
935 })
936 .collect()
937 }
938
939 fn add_getter_instead_of_mut_arg_if_applicable(
940 wrappers: &BTreeMap<String, CWrapper>,
941 method: &Method,
942 fn_name: &Ident,
943 where_clause: &TokenStream,
944 possible_self: &TokenStream,
945 method_docs: &Vec<TokenStream>,
946 additional_methods: &mut Vec<TokenStream>,
947 debug_fields: &mut Vec<TokenStream>,
948 ) {
949 if ["constants", "buffers", "values"]
950 .iter()
951 .any(|name| method.struct_method_name == *name)
952 && method.arguments.len() == 2
953 {
954 let rt = ReturnType::new(method.arguments[1].clone(), wrappers.clone());
955 let return_type = rt.get_new_return_type(false, false);
956 let getter_method = format_ident!("get_{}", fn_name);
957 let method_docs = method_docs
958 .iter()
959 .cloned()
960 .take_while(|t| !t.to_string().contains(" Parameter"))
961 .collect_vec();
962 additional_methods.push(quote! {
963 #[inline]
964 #(#method_docs)*
965 pub fn #getter_method #where_clause(#possible_self) -> Result<#return_type, AeronCError> {
966 let result = #return_type::new_zeroed_on_stack();
967 self.#fn_name(&result)?;
968 Ok(result)
969 }
970 });
971 debug_fields.push(quote! {
972 .field(stringify!(#fn_name), &self.#getter_method() )
973 });
974 }
975 }
976
977 fn add_mut_string_methods_if_applicable(
978 method: &Method,
979 fn_name: &Ident,
980 uses_self: bool,
981 method_docs: &Vec<TokenStream>,
982 additional_methods: &mut Vec<TokenStream>,
983 ) {
984 if method.arguments.len() == 3 && uses_self {
985 let method_docs = method_docs.clone();
986 let into_method = format_ident!("{}_into", fn_name);
987 if method.arguments[1].is_mut_c_string() && method.arguments[2].is_usize() {
988 let string_method = format_ident!("{}_as_string", fn_name);
989 additional_methods.push(quote! {
990 #[inline]
991 #(#method_docs)*
992 pub fn #string_method(
993 &self,
994 max_length: usize,
995 ) -> Result<String, AeronCError> {
996 let mut result = String::with_capacity(max_length);
997 self.#into_method(&mut result)?;
998 Ok(result)
999 }
1000
1001 #[inline]
1002 #(#method_docs)*
1003 #[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"]
1004 pub fn #into_method(
1005 &self,
1006 dst_truncate_to_capacity: &mut String,
1007 ) -> Result<i32, AeronCError> {
1008 unsafe {
1009 let capacity = dst_truncate_to_capacity.capacity();
1010 let vec = dst_truncate_to_capacity.as_mut_vec();
1011 vec.set_len(capacity);
1012 let result = self.#fn_name(&mut vec[..])?;
1013 let mut len = 0;
1014 loop {
1015 if len == capacity {
1016 break;
1017 }
1018 let val = vec[len];
1019 if val == 0 {
1020 break;
1021 }
1022 len += 1;
1023 }
1024 vec.set_len(len);
1025 Ok(result)
1026 }
1027 }
1028 });
1029 }
1030 }
1031 }
1032
1033 fn generate_fields(
1035 &self,
1036 cwrappers: &BTreeMap<String, CWrapper>,
1037 debug_fields: &mut Vec<TokenStream>,
1038 ) -> Vec<TokenStream> {
1039 self.fields
1040 .iter()
1041 .filter(|arg| {
1042 !arg.name.starts_with("_") && !self.methods.iter().any(|m| m.struct_method_name.as_str() == arg.name)
1043 })
1044 .map(|arg| {
1045 let field_name = &arg.name;
1046 let fn_name = Ident::new(field_name, proc_macro2::Span::call_site());
1047
1048 let mut arg = arg.clone();
1049 if arg.is_mut_c_string() {
1051 arg.c_type = arg.c_type.replace(" mut ", " const ");
1052 }
1053 let mut rt = ReturnType::new(arg.clone(), cwrappers.clone());
1054 let mut return_type = rt.get_new_return_type(false, false);
1055 let handler = if let ArgProcessing::Handler(_) = &arg.processing {
1056 true
1057 } else {
1058 false
1059 };
1060 if return_type.is_empty() || handler {
1061 rt = ReturnType::new(
1062 Arg {
1063 processing: ArgProcessing::Default,
1064 ..arg.clone()
1065 },
1066 cwrappers.clone(),
1067 );
1068 return_type = rt.get_new_return_type(false, false);
1069 }
1070 let converter = rt.handle_c_to_rs_return(quote! { self.#fn_name }, false, true);
1071
1072 if rt.original.is_primitive()
1073 || rt.original.is_c_string_any()
1074 || rt.original.is_byte_array()
1075 || cwrappers.contains_key(&rt.original.c_type)
1076 {
1077 if !rt.original.is_any_pointer() || rt.original.is_c_string_any() {
1078 debug_fields.push(quote! { .field(stringify!(#fn_name), &self.#fn_name()) });
1079 }
1080 }
1081
1082 quote! {
1083 #[inline]
1084 pub fn #fn_name(&self) -> #return_type {
1085 #converter
1086 }
1087 }
1088 })
1089 .filter(|t| !t.is_empty())
1090 .collect()
1091 }
1092
1093 fn generate_constructor(
1095 &self,
1096 wrappers: &BTreeMap<String, CWrapper>,
1097 constructor_fields: &mut Vec<TokenStream>,
1098 new_ref_set_none: &mut Vec<TokenStream>,
1099 ) -> Vec<TokenStream> {
1100 let constructors = self
1101 .methods
1102 .iter()
1103 .filter(|m| m.arguments.iter().any(|arg| arg.is_double_mut_pointer()))
1104 .map(|method| {
1105 let init_fn = format_ident!("{}", method.fn_name);
1106 let close_method = self.find_close_method(method);
1107 let found_close = close_method.is_some()
1108 && close_method.unwrap().return_type.is_c_raw_int()
1109 && close_method.unwrap() != method
1110 && close_method
1111 .unwrap()
1112 .arguments
1113 .iter()
1114 .skip(1)
1115 .all(|a| method.arguments.iter().any(|a2| a.name == a2.name));
1116 if found_close {
1117 let close_fn = format_ident!("{}", close_method.unwrap().fn_name);
1118 let init_args: Vec<TokenStream> = method
1119 .arguments
1120 .iter()
1121 .enumerate()
1122 .map(|(idx, arg)| {
1123 if idx == 0 {
1124 quote! { ctx_field }
1125 } else {
1126 let arg_name = arg.as_ident();
1127 quote! { #arg_name }
1128 }
1129 })
1130 .filter(|t| !t.is_empty())
1131 .collect();
1132 let close_args: Vec<TokenStream> = close_method
1133 .unwrap_or(method)
1134 .arguments
1135 .iter()
1136 .enumerate()
1137 .map(|(idx, arg)| {
1138 if idx == 0 {
1139 if arg.is_double_mut_pointer() {
1140 quote! { ctx_field }
1141 } else {
1142 quote! { *ctx_field }
1143 }
1144 } else {
1145 let arg_name = arg.as_ident();
1146 quote! { #arg_name.into() }
1147 }
1148 })
1149 .filter(|t| !t.is_empty())
1150 .collect();
1151 let lets: Vec<TokenStream> = Self::lets_for_copying_arguments(wrappers, &method.arguments, true);
1152
1153 constructor_fields.clear();
1154 constructor_fields.extend(Self::constructor_fields(wrappers, &method.arguments, &self.class_name));
1155
1156 let new_ref_args = Self::new_args(wrappers, &method.arguments, &self.class_name, false);
1157
1158 new_ref_set_none.clear();
1159 new_ref_set_none.extend(Self::new_args(wrappers, &method.arguments, &self.class_name, true));
1160
1161 let new_args: Vec<TokenStream> = method
1162 .arguments
1163 .iter()
1164 .enumerate()
1165 .filter_map(|(_idx, arg)| {
1166 if arg.is_double_mut_pointer() {
1167 None
1168 } else {
1169 let arg_name = arg.as_ident();
1170 let arg_type =
1171 ReturnType::new(arg.clone(), wrappers.clone()).get_new_return_type(false, true);
1172 if arg_type.clone().into_token_stream().is_empty() {
1173 None
1174 } else {
1175 Some(quote! { #arg_name: #arg_type })
1176 }
1177 }
1178 })
1179 .filter(|t| !t.is_empty())
1180 .collect();
1181
1182 let fn_name = format_ident!(
1183 "{}",
1184 method
1185 .struct_method_name
1186 .replace("init", "new")
1187 .replace("create", "new")
1188 );
1189
1190 let generic_types: Vec<TokenStream> = method
1191 .arguments
1192 .iter()
1193 .flat_map(|arg| {
1194 ReturnType::new(arg.clone(), wrappers.clone())
1195 .method_generics_for_where(true)
1196 .into_iter()
1197 })
1198 .collect_vec();
1199 let where_clause = if generic_types.is_empty() {
1200 quote! {}
1201 } else {
1202 quote! { <#(#generic_types),*> }
1203 };
1204
1205 let method_docs: Vec<TokenStream> = get_docs(&method.docs, wrappers, Some(&new_args));
1206
1207 let handler_deps: Vec<TokenStream> = Self::handler_dependency_registrations(&method.arguments);
1212
1213 let init_log_expr_tokens = Self::generate_arg_logging(&method.arguments, &init_args);
1215 let close_log_expr_tokens = if let Some(close_m) = close_method {
1217 Self::generate_arg_logging(&close_m.arguments, &close_args)
1218 } else {
1219 quote! { "" }
1220 };
1221
1222 let cleanup_tokens = if method.fn_name.contains("_destination") {
1229 quote! { None }
1230 } else {
1231 quote! {
1232 Some(Box::new(move |ctx_field| unsafe {
1233 #[cfg(feature = "log-c-bindings")]
1234 {
1235 let log_args = #close_log_expr_tokens;
1236 log::info!("{}({})", stringify!(#close_fn), log_args);
1237 }
1238 #close_fn(#(#close_args),*)
1239 }))
1240 }
1241 };
1242
1243 quote! {
1244 #[inline]
1245 #(#method_docs)*
1246 pub fn #fn_name #where_clause(#(#new_args),*) -> Result<Self, AeronCError> {
1247 #(#lets)*
1248 let resource_constructor = ManagedCResource::new(
1250 move |ctx_field| unsafe {
1251 #[cfg(feature = "log-c-bindings")]
1252 {
1253 let log_args = #init_log_expr_tokens;
1254 log::info!("{}({})", stringify!(#init_fn), log_args);
1255 }
1256 #init_fn(#(#init_args),*)
1257 },
1258 #cleanup_tokens,
1259 false,
1260 )?;
1261
1262 let result = Self {
1263 inner: CResource::OwnedOnHeap(RcOrArc::new(resource_constructor)),
1264 #(#new_ref_args)*
1265 };
1266 #(#handler_deps)*
1267 Ok(result)
1268 }
1269 }
1270 } else {
1271 quote! {}
1272 }
1273 })
1274 .collect_vec();
1275
1276 let no_constructor = constructors.iter().map(|x| x.to_string()).join("").trim().is_empty();
1277 if no_constructor {
1278 let type_name = format_ident!("{}", self.type_name);
1279 let zeroed_impl = quote! {
1280 #[inline]
1281 pub fn new_zeroed_on_heap() -> Self {
1283 let resource = ManagedCResource::new(
1284 move |ctx_field| {
1285 #[cfg(feature = "extra-logging")]
1286 log::info!("creating zeroed empty resource on heap {}", stringify!(#type_name));
1287 let inst: #type_name = unsafe { std::mem::zeroed() };
1288 let inner_ptr: *mut #type_name = Box::into_raw(Box::new(inst));
1289 unsafe { *ctx_field = inner_ptr };
1290 0
1291 },
1292 None,
1293 true,
1294 ).unwrap();
1295
1296 Self {
1297 inner: CResource::OwnedOnHeap(RcOrArc::new(resource)),
1298 }
1299 }
1300
1301 #[inline]
1302 pub fn new_zeroed_on_stack() -> Self {
1305 #[cfg(feature = "extra-logging")]
1306 log::debug!("creating zeroed empty resource on stack {}", stringify!(#type_name));
1307
1308 Self {
1309 inner: CResource::OwnedOnStack(std::mem::MaybeUninit::zeroed()),
1310 }
1311 }
1312 };
1313 if self.has_default_method() {
1314 let type_name = format_ident!("{}", self.type_name);
1315 let new_args: Vec<TokenStream> = self
1316 .fields
1317 .iter()
1318 .filter_map(|arg| {
1319 let arg_name = arg.as_ident();
1320 let arg_type = ReturnType::new(arg.clone(), wrappers.clone()).get_new_return_type(false, true);
1321 if arg_type.is_empty() {
1322 None
1323 } else {
1324 Some(quote! { #arg_name: #arg_type })
1325 }
1326 })
1327 .filter(|t| !t.is_empty())
1328 .collect();
1329 let init_args: Vec<TokenStream> = self
1330 .fields
1331 .iter()
1332 .map(|arg| {
1333 let arg_name = arg.as_ident();
1334 let value = ReturnType::new(arg.clone(), wrappers.clone())
1335 .handle_rs_to_c_return(quote! { #arg_name }, true);
1336 quote! { #value }
1337 })
1338 .filter(|t| !t.is_empty())
1339 .collect();
1340
1341 let generic_types: Vec<TokenStream> = self
1342 .fields
1343 .iter()
1344 .flat_map(|arg| {
1345 ReturnType::new(arg.clone(), wrappers.clone())
1346 .method_generics_for_where(true)
1347 .into_iter()
1348 })
1349 .collect_vec();
1350 let where_clause = if generic_types.is_empty() {
1351 quote! {}
1352 } else {
1353 quote! { <#(#generic_types),*> }
1354 };
1355
1356 let cloned_fields = self
1357 .fields
1358 .iter()
1359 .filter(|a| a.processing == ArgProcessing::Default)
1360 .cloned()
1361 .collect_vec();
1362 let lets: Vec<TokenStream> = Self::lets_for_copying_arguments(wrappers, &cloned_fields, false);
1363
1364 let field_handler_deps: Vec<TokenStream> = Self::handler_dependency_registrations(&self.fields);
1367
1368 vec![quote! {
1369 #[inline]
1370 pub fn new #where_clause(#(#new_args),*) -> Result<Self, AeronCError> {
1371 #(#lets)*
1372 let r_constructor = ManagedCResource::new(
1374 move |ctx_field| {
1375 let inst = #type_name { #(#init_args),* };
1376 let inner_ptr: *mut #type_name = Box::into_raw(Box::new(inst));
1377 unsafe { *ctx_field = inner_ptr };
1378 0
1379 },
1380 None,
1381 true,
1382 )?;
1383
1384 let result = Self {
1385 inner: CResource::OwnedOnHeap(RcOrArc::new(r_constructor)),
1386 };
1387 #(#field_handler_deps)*
1388 Ok(result)
1389 }
1390
1391 #zeroed_impl
1392 }]
1393 } else {
1394 vec![zeroed_impl]
1395 }
1396 } else {
1397 constructors
1398 }
1399 }
1400
1401 fn lets_for_copying_arguments(
1402 wrappers: &BTreeMap<String, CWrapper>,
1403 arguments: &Vec<Arg>,
1404 include_let_statements: bool,
1405 ) -> Vec<TokenStream> {
1406 arguments
1407 .iter()
1408 .enumerate()
1409 .filter_map(|(_idx, arg)| {
1410 if arg.is_double_mut_pointer() {
1411 None
1412 } else {
1413 let arg_name = arg.as_ident();
1414 let rtype = arg.as_type();
1415
1416 let fields = if arg.is_single_mut_pointer()
1418 && wrappers.contains_key(arg.c_type.split_whitespace().last().unwrap())
1419 {
1420 let arg_copy = format_ident!("{}_copy", arg.name);
1421 quote! {
1422 let #arg_copy = #arg_name.clone();
1423 }
1424 } else {
1425 quote! {}
1426 };
1427
1428 let return_type = ReturnType::new(arg.clone(), wrappers.clone());
1429
1430 if let ArgProcessing::StringWithLength(_args) | ArgProcessing::ByteArrayWithLength(_args) =
1431 &return_type.original.processing
1432 {
1433 return None;
1434 }
1435 if let ArgProcessing::Handler(args) = &return_type.original.processing {
1436 let arg1 = args[0].as_ident();
1437 let arg2 = args[1].as_ident();
1438 let value = return_type.handle_rs_to_c_return(quote! { #arg_name }, false);
1439
1440 if value.is_empty() {
1441 return None;
1442 }
1443
1444 if include_let_statements {
1445 return Some(quote! { #fields let (#arg1, #arg2)= (#value); });
1446 } else {
1447 return Some(fields);
1448 }
1449 }
1450
1451 let value = return_type.handle_rs_to_c_return(quote! { #arg_name }, false);
1452 if value.is_empty() {
1453 None
1454 } else {
1455 if include_let_statements {
1456 Some(quote! { #fields let #arg_name: #rtype = #value; })
1457 } else {
1458 return Some(fields);
1459 }
1460 }
1461 }
1462 })
1463 .filter(|t| !t.is_empty())
1464 .collect()
1465 }
1466
1467 fn constructor_fields(
1468 wrappers: &BTreeMap<String, CWrapper>,
1469 arguments: &Vec<Arg>,
1470 class_name: &String,
1471 ) -> Vec<TokenStream> {
1472 if class_name == "AeronAsyncDestination" {
1473 return vec![];
1474 }
1475
1476 arguments
1477 .iter()
1478 .enumerate()
1479 .filter_map(|(_idx, arg)| {
1480 if arg.is_double_mut_pointer() {
1481 None
1482 } else {
1483 let arg_name = arg.as_ident();
1484 let rtype = arg.as_type();
1485 if arg.is_single_mut_pointer()
1486 && wrappers.contains_key(arg.c_type.split_whitespace().last().unwrap())
1487 {
1488 let return_type = ReturnType::new(arg.clone(), wrappers.clone());
1489 let return_type = return_type.get_new_return_type(false, false);
1490
1491 let arg_copy = format_ident!("_{}", arg.name);
1492 Some(quote! {
1493 #arg_copy: Option<#return_type>,
1494 })
1495 } else {
1496 None
1497 }
1498 }
1499 })
1500 .collect()
1501 }
1502
1503 fn new_args(
1504 wrappers: &BTreeMap<String, CWrapper>,
1505 arguments: &Vec<Arg>,
1506 class_name: &String,
1507 set_none: bool,
1508 ) -> Vec<TokenStream> {
1509 if class_name == "AeronAsyncDestination" {
1510 return vec![];
1511 }
1512
1513 arguments
1514 .iter()
1515 .enumerate()
1516 .filter_map(|(_idx, arg)| {
1517 if arg.is_double_mut_pointer() {
1518 None
1519 } else {
1520 let arg_name = arg.as_ident();
1521 let rtype = arg.as_type();
1522 if arg.is_single_mut_pointer()
1523 && wrappers.contains_key(arg.c_type.split_whitespace().last().unwrap())
1524 {
1525 let arg_f = format_ident!("_{}", &arg.name);
1526 let arg_copy = format_ident!("{}_copy", &arg.name);
1527 if set_none {
1528 Some(quote! {
1529 #arg_f: None,
1530 })
1531 } else {
1532 Some(quote! {
1533 #arg_f: Some(#arg_copy),
1534 })
1535 }
1536 } else {
1537 None
1538 }
1539 }
1540 })
1541 .collect()
1542 }
1543
1544 fn find_close_method(&self, method: &Method) -> Option<&Method> {
1545 let mut close_method = None;
1546
1547 if ["_init", "_create", "_add"]
1549 .iter()
1550 .all(|find| !method.fn_name.contains(find))
1551 {
1552 return None;
1553 }
1554
1555 for name in ["_destroy", "_delete"] {
1556 let close_fn = format_ident!(
1557 "{}",
1558 method
1559 .fn_name
1560 .replace("_init", "_close")
1561 .replace("_create", name)
1562 .replace("_add_", "_remove_")
1563 );
1564 let method = self.methods.iter().find(|m| close_fn.to_string().contains(&m.fn_name));
1565 if method.is_some() {
1566 close_method = method;
1567 break;
1568 }
1569 }
1570 close_method
1571 }
1572
1573 fn has_default_method(&self) -> bool {
1574 let no_init_method = !self.methods.iter().any(|m| {
1576 m.arguments
1577 .iter()
1578 .any(|arg| arg.is_double_mut_pointer() || (arg.is_single_mut_pointer() && m.fn_name.contains("_init_")))
1579 });
1580
1581 no_init_method && !self.fields.iter().any(|arg| arg.name.starts_with("_")) && !self.fields.is_empty()
1582 }
1583
1584 fn generate_allocation_test(&self) -> TokenStream {
1585 let class_name = format_ident!("{}", self.class_name);
1586
1587 let has_c_constructor = self
1588 .methods
1589 .iter()
1590 .any(|m| m.arguments.iter().any(|arg| arg.is_double_mut_pointer()));
1591 let has_empty_new_constructor = self.methods.iter().any(|m| {
1592 m.fn_name.contains("_init_")
1593 && m.arguments.iter().any(|arg| arg.is_double_mut_pointer())
1594 && m.arguments.len() == 1
1595 });
1596
1597 let mut tests = vec![];
1598
1599 if !has_c_constructor {
1600 tests.push(quote! {
1601 #[test]
1602 #[file_serial(global)]
1603 fn test_new_on_stack() {
1604 crate::test_alloc::assert_no_allocation(|| {
1605 for _ in 0..100 {
1606 let _ = #class_name::new_zeroed_on_stack();
1607 }
1608 });
1609 }
1610 });
1611 }
1612
1613 if has_empty_new_constructor {
1614 tests.push(quote! {
1615 #[test]
1616 #[file_serial(global)]
1617 fn test_new() {
1618 crate::test_alloc::assert_no_allocation(|| {
1619 for _ in 0..100 {
1620 let _ = #class_name::new();
1621 }
1622 });
1623 }
1624 });
1625 }
1626
1627 if self.has_default_method() {
1628 tests.push(quote! {
1629 #[test]
1630 #[file_serial(global)]
1631 fn test_default() {
1632 crate::test_alloc::assert_no_allocation(|| {
1633 for _ in 0..100 {
1634 let _ = #class_name::default();
1635 }
1636 });
1637 }
1638 });
1639 }
1640
1641 let mod_name = format_ident!("{}_allocation_tests", self.type_name);
1642
1643 if tests.is_empty() {
1644 quote! {}
1645 } else {
1646 quote! {
1647 #[cfg(test)]
1648 mod #mod_name {
1649 use super::*;
1650 use serial_test::file_serial;
1651 #(#tests)*
1652 }
1653 }
1654 }
1655 }
1656}
1657
1658#[cfg(test)]
1659mod parse_custom_methods_tests {
1660 use super::parse_custom_methods;
1661 use std::collections::BTreeSet;
1662
1663 #[test]
1664 fn extracts_method_names_from_inherent_impls() {
1665 let src = r#"
1666 impl AeronPublication {
1667 pub fn offer_result(&self) -> i64 { 0 }
1668 pub fn status(&self) -> u8 { 0 }
1669 }
1670 impl AeronSubscription {
1671 pub fn status(&self) -> u8 { 0 }
1672 }
1673 "#;
1674 let map = parse_custom_methods(src);
1675 assert_eq!(
1676 map.get("AeronPublication"),
1677 Some(
1678 &["offer_result", "status"]
1679 .iter()
1680 .map(|s| s.to_string())
1681 .collect::<BTreeSet<_>>()
1682 )
1683 );
1684 assert!(map.get("AeronSubscription").map_or(false, |s| s.contains("status")));
1685 }
1686
1687 #[test]
1688 fn ignores_trait_impls() {
1689 let src = r#"
1692 impl std::fmt::Display for AeronCError {
1693 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Ok(()) }
1694 }
1695 "#;
1696 let map = parse_custom_methods(src);
1697 assert!(
1698 !map.contains_key("AeronCError"),
1699 "trait impls must not appear in the skip-list"
1700 );
1701 }
1702
1703 #[test]
1704 #[should_panic(expected = "failed to parse aeron_custom.rs")]
1705 fn panics_loudly_on_malformed_input() {
1706 let _ = parse_custom_methods("impl { not valid rust }}}");
1708 }
1709
1710 #[test]
1711 fn empty_input_yields_empty_map() {
1712 assert!(parse_custom_methods("").is_empty());
1713 }
1714
1715 #[test]
1716 fn self_type_keyed_by_plain_token_stream() {
1717 let src = r#"
1718 impl AeronPublication { pub fn offer_result(&self) -> i64 { 0 } }
1719 "#;
1720 let map = parse_custom_methods(src);
1721 assert_eq!(map.len(), 1);
1723 assert!(map.contains_key("AeronPublication"));
1724 }
1725}
1726
1727#[cfg(test)]
1728mod arg_classification_tests {
1729 use super::{Arg, ArgProcessing};
1730
1731 fn arg(c_type: &str) -> Arg {
1732 Arg {
1733 name: "x".to_string(),
1734 c_type: c_type.to_string(),
1735 processing: ArgProcessing::Default,
1736 }
1737 }
1738
1739 #[test]
1740 fn classifies_c_strings() {
1741 assert!(arg("* const :: std :: os :: raw :: c_char").is_c_string());
1742 assert!(arg("* const :: std :: os :: raw :: c_char").is_c_string_any());
1743 assert!(arg("* mut :: std :: os :: raw :: c_char").is_mut_c_string());
1744 assert!(arg("* mut :: std :: os :: raw :: c_char").is_c_string_any());
1745 assert!(!arg("* const u8").is_c_string());
1747 assert!(!arg("i32").is_c_string_any());
1748 }
1749
1750 #[test]
1751 fn classifies_byte_arrays() {
1752 assert!(arg("* const u8").is_byte_array());
1753 assert!(arg("* mut u8").is_byte_array());
1754 assert!(arg("* mut u8").is_mut_byte_array());
1755 assert!(!arg("* const u8").is_mut_byte_array());
1756 assert!(!arg("* const :: std :: os :: raw :: c_char").is_byte_array());
1757 }
1758
1759 #[test]
1760 fn classifies_raw_int_return() {
1761 assert!(arg(":: std :: os :: raw :: c_int").is_c_raw_int());
1762 assert!(!arg("i32").is_c_raw_int());
1763 }
1764
1765 #[test]
1766 fn classifies_void_pointer() {
1767 assert!(arg("* mut :: std :: os :: raw :: c_void").is_c_void());
1768 assert!(!arg("* mut u8").is_c_void());
1769 }
1770
1771 #[test]
1772 fn classifies_mut_pointers_single_vs_double() {
1773 assert!(arg("* mut i32").is_mut_pointer());
1775 assert!(arg("* mut i32").is_single_mut_pointer());
1776 assert!(!arg("* mut i32").is_double_mut_pointer());
1777 assert!(arg("* mut * mut aeron_foo_t").is_mut_pointer());
1779 assert!(arg("* mut * mut aeron_foo_t").is_double_mut_pointer());
1780 assert!(!arg("* mut * mut aeron_foo_t").is_single_mut_pointer());
1781 assert!(!arg("* const i32").is_mut_pointer());
1783 }
1784
1785 #[test]
1786 fn classifies_primitives() {
1787 for ty in [
1788 "i64", "u64", "f32", "f64", "i32", "i16", "u32", "u16", "bool", "usize", "isize",
1789 ] {
1790 assert!(arg(ty).is_primitive(), "{ty} should be primitive");
1791 }
1792 assert!(arg("* mut i32").is_primitive());
1797 assert!(!arg("* mut aeron_foo_t").is_primitive());
1799 }
1800
1801 #[test]
1802 fn classifies_any_pointer() {
1803 assert!(arg("* const i32").is_any_pointer());
1804 assert!(arg("* mut i32").is_any_pointer());
1805 assert!(!arg("i32").is_any_pointer());
1806 }
1807}
1808
1809fn get_docs(
1810 docs: &BTreeSet<String>,
1811 wrappers: &BTreeMap<String, CWrapper>,
1812 arguments: Option<&Vec<TokenStream>>,
1813) -> Vec<TokenStream> {
1814 let mut first_param = true;
1815 docs.iter()
1816 .flat_map(|d| d.lines())
1817 .filter(|s| {
1818 arguments.is_none()
1819 || !s.contains("@param")
1820 || (s.contains("@param")
1821 && arguments
1822 .unwrap()
1823 .iter()
1824 .any(|a| s.contains(format!(" {}", a.to_string().split_whitespace().next().unwrap()).as_str())))
1825 })
1826 .map(|doc| {
1827 let mut doc = doc.to_string();
1828
1829 if first_param && doc.contains("@param") {
1830 doc = format!("# Parameters\n{}", doc);
1831 first_param = false;
1832 }
1833
1834 if doc.contains("@param") {
1835 doc = regex::Regex::new("@param\\s+([^ ]+)")
1836 .unwrap()
1837 .replace(doc.as_str(), "\n - `$1`")
1838 .to_string();
1839 }
1840
1841 doc = doc
1842 .replace("@return", "\n# Return\n")
1843 .replace("<p>", "\n")
1844 .replace("</p>", "\n");
1845
1846 doc = wrappers
1847 .values()
1848 .fold(doc, |acc, v| acc.replace(&v.type_name, &format!("`{}`", v.class_name)));
1849
1850 if doc.contains("@deprecated") {
1851 quote! {
1852 #[deprecated]
1853 #[doc = #doc]
1854 }
1855 } else {
1856 quote! {
1857 #[doc = #doc]
1858 }
1859 }
1860 })
1861 .collect()
1862}
1863
1864fn generate_stateless_handler_code(handler: &CHandler) -> TokenStream {
1865 let type_name_ident = format_ident!("{}", handler.type_name);
1866 let callback_fn_name = format_ident!("{}_callback", handler.type_name);
1867 let closure_type_name = format_ident!("{}Callback", snake_to_pascal_case(&handler.type_name));
1868 let logger_type_name = format_ident!("{}Logger", snake_to_pascal_case(&handler.type_name));
1869 let handle_method_name = format_ident!("handle_{}", &handler.type_name[..handler.type_name.len() - 2]);
1870 let closure_return_type = handler.return_type.as_type();
1871
1872 let (fn_mut_args, trait_args): (Vec<TokenStream>, Vec<TokenStream>) = handler
1874 .args
1875 .iter()
1876 .enumerate()
1877 .map(|(i, arg)| {
1878 let return_type = ReturnType::new(arg.clone(), BTreeMap::new());
1879 let type_name = return_type.get_new_return_type(false, false);
1880 let arg_name = format_ident!("arg_{}", i);
1881
1882 let fn_mut_arg = if arg.is_single_mut_pointer() && arg.is_primitive() {
1883 let owned_type: Type = parse_str(arg.c_type.split_whitespace().last().unwrap()).unwrap();
1884 quote! { #owned_type }
1885 } else {
1886 quote! { #type_name }
1887 };
1888
1889 let trait_arg = if type_name.is_empty() {
1890 quote! {}
1891 } else if arg.is_single_mut_pointer() && arg.is_primitive() {
1892 let owned_type: Type = parse_str(arg.c_type.split_whitespace().last().unwrap()).unwrap();
1893 quote! { #arg_name: #owned_type }
1894 } else {
1895 quote! { #arg_name: #type_name }
1896 };
1897
1898 (fn_mut_arg, trait_arg)
1899 })
1900 .filter(|(fn_mut, trait_)| !fn_mut.is_empty() && !trait_.is_empty())
1901 .unzip();
1902
1903 let fn_mut_sig = quote! {
1905 FnMut(#(#fn_mut_args),*) -> #closure_return_type
1906 };
1907
1908 quote! {
1909 pub trait #closure_type_name {
1910 fn #handle_method_name(&mut self, #(#trait_args),*) -> #closure_return_type;
1911 }
1912
1913 pub struct #logger_type_name;
1914 impl #closure_type_name for #logger_type_name {
1915 fn #handle_method_name(&mut self, #(#trait_args),*) -> #closure_return_type {
1916 log::info!(
1917 "{}({}\n)",
1918 stringify!(#handle_method_name),
1919 ""
1920 );
1921 unimplemented!()
1922 }
1923 }
1924
1925 #[allow(dead_code)]
1927 unsafe extern "C" fn #callback_fn_name<F: #closure_type_name>(#(#trait_args),*) -> #closure_return_type {
1928 unimplemented!("Stateless handler callback called - not supported")
1929 }
1930 }
1931}
1932
1933pub fn generate_handlers(handler: &mut CHandler, bindings: &CBinding) -> TokenStream {
1934 if handler
1935 .args
1936 .iter()
1937 .any(|arg| arg.is_primitive() && arg.is_mut_pointer())
1938 {
1939 return quote! {};
1940 }
1941
1942 let has_c_void_param = handler.args.iter().any(|a| a.is_c_void());
1946 let is_stateless = !has_c_void_param;
1947
1948 if is_stateless {
1949 let closure_type_name = format_ident!("{}Callback", snake_to_pascal_case(&handler.type_name));
1950 let fn_mut_args: Vec<TokenStream> = handler
1952 .args
1953 .iter()
1954 .map(|arg| {
1955 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
1956 let type_name = return_type.get_new_return_type(false, false);
1957 if arg.is_single_mut_pointer() && arg.is_primitive() {
1958 let owned_type: Type = parse_str(arg.c_type.split_whitespace().last().unwrap()).unwrap();
1959 quote! { #owned_type }
1960 } else {
1961 quote! { #type_name }
1962 }
1963 })
1964 .filter(|t| !t.is_empty())
1965 .collect();
1966 let closure_return_type = handler.return_type.as_type();
1967 handler.fn_mut_signature = quote! {
1968 FnMut(#(#fn_mut_args),*) -> #closure_return_type
1969 };
1970 handler.closure_type_name = quote! {
1971 #closure_type_name
1972 };
1973 return generate_stateless_handler_code(handler);
1974 }
1975
1976 let fn_name = format_ident!("{}_callback", handler.type_name);
1977 let closure_fn_name = format_ident!("{}_callback_for_once_closure", handler.type_name);
1978 let doc_comments: Vec<TokenStream> = handler
1979 .docs
1980 .iter()
1981 .flat_map(|doc| doc.lines())
1982 .map(|line| quote! { #[doc = #line] })
1983 .collect();
1984
1985 let closure = handler
1986 .args
1987 .iter()
1988 .find(|a| a.is_c_void())
1989 .map(|a| a.name.clone())
1990 .unwrap_or_else(|| "state".to_string());
1991 let closure_name = format_ident!("{}", closure);
1992 let closure_type_name = format_ident!("{}Callback", snake_to_pascal_case(&handler.type_name));
1993 let closure_return_type = handler.return_type.as_type();
1994
1995 let logger_type_name = format_ident!("{}Logger", snake_to_pascal_case(&handler.type_name));
1996
1997 let handle_method_name = format_ident!("handle_{}", &handler.type_name[..handler.type_name.len() - 2]);
1998
1999 let no_method_name = format_ident!(
2000 "no_{}_handler",
2001 &handler.type_name[..handler.type_name.len() - 2]
2002 .replace("_on_", "_")
2003 .replace("aeron_", "")
2004 );
2005
2006 let args: Vec<TokenStream> = handler
2007 .args
2008 .iter()
2009 .map(|arg| {
2010 let arg_name = arg.as_ident();
2011 let arg_type: Type = arg.as_type();
2013 quote! { #arg_name: #arg_type }
2014 })
2015 .filter(|t| !t.is_empty())
2016 .collect();
2017
2018 let arg_names_for_logging: Vec<TokenStream> = handler
2019 .args
2020 .iter()
2021 .map(|arg| {
2022 let arg_name = arg.as_ident();
2023 quote! { format!("{} = {:?}", stringify!(#arg_name), #arg_name) }
2024 })
2025 .collect();
2026
2027 let converted_args: Vec<TokenStream> = handler
2028 .args
2029 .iter()
2030 .filter_map(|arg| {
2031 let name = &arg.name;
2032 let arg_name = arg.as_ident();
2033 if name == &closure {
2036 None
2037 } else {
2038 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
2039 Some(return_type.handle_c_to_rs_return(quote! {#arg_name}, false, false))
2040 }
2041 })
2042 .filter(|t| !t.is_empty())
2043 .collect();
2044
2045 let closure_args: Vec<TokenStream> = handler
2046 .args
2047 .iter()
2048 .filter_map(|arg| {
2049 let name = &arg.name;
2050 if name == &closure {
2051 return None;
2052 }
2053
2054 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
2055 let type_name = return_type.get_new_return_type(false, false);
2056 let field_name = format_ident!("{}", name);
2057 if type_name.is_empty() {
2058 None
2059 } else {
2060 Some(quote! {
2061 #field_name: #type_name
2062 })
2063 }
2064 })
2065 .filter(|t| !t.is_empty())
2066 .collect();
2067
2068 let mut log_field_names = vec![];
2069 let closure_args_in_logger: Vec<TokenStream> = handler
2070 .args
2071 .iter()
2072 .filter_map(|arg| {
2073 let name = &arg.name;
2074 if name == &closure {
2075 return None;
2076 }
2077
2078 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
2079 let type_name = return_type.get_new_return_type(false, false);
2080 let field_name = format_ident!("{}", name);
2081 if type_name.is_empty() {
2082 None
2083 } else {
2084 log_field_names.push(Some(
2085 quote! { format!("{} : {:?}", stringify!(#field_name), #field_name) },
2086 ));
2087
2088 Some(quote! {
2089 #field_name: #type_name
2090 })
2091 }
2092 })
2093 .filter(|t| !t.is_empty())
2094 .collect();
2095
2096 if log_field_names.is_empty() {
2097 log_field_names.push(Some(quote! { "" }));
2098 }
2099
2100 let fn_mut_args: Vec<TokenStream> = handler
2101 .args
2102 .iter()
2103 .filter_map(|arg| {
2104 let name = &arg.name;
2105 if name == &closure {
2106 return None;
2107 }
2108
2109 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
2110 let type_name = return_type.get_new_return_type(false, false);
2111 if arg.is_single_mut_pointer() && arg.is_primitive() {
2112 let owned_type: Type = parse_str(arg.c_type.split_whitespace().last().unwrap()).unwrap();
2113 return Some(quote! { #owned_type });
2114 } else {
2115 return Some(quote! {
2116 #type_name
2117 });
2118 }
2119 })
2120 .filter(|t| !t.is_empty())
2121 .collect();
2122
2123 handler.fn_mut_signature = quote! {
2124 FnMut(#(#fn_mut_args),*) -> #closure_return_type
2125 };
2126 handler.closure_type_name = quote! {
2127 #closure_type_name
2128 };
2129
2130 let logger_return_type = if closure_return_type.to_token_stream().to_string().eq("()") {
2131 closure_return_type.clone().to_token_stream()
2132 } else {
2133 quote! {
2134 unimplemented!()
2135 }
2136 };
2137
2138 let wrapper_closure_args: Vec<TokenStream> = handler
2139 .args
2140 .iter()
2141 .filter_map(|arg| {
2142 let name = &arg.name;
2143 if name == &closure {
2144 return None;
2145 }
2146
2147 let field_name = format_ident!("{}", name);
2148 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone()).get_new_return_type(false, false);
2149 if return_type.is_empty() {
2150 None
2151 } else {
2152 Some(quote! { #field_name })
2153 }
2154 })
2155 .filter(|t| !t.is_empty())
2156 .collect();
2157
2158 quote! {
2159 #(#doc_comments)*
2160 pub trait #closure_type_name {
2164 fn #handle_method_name(&mut self, #(#closure_args),*) -> #closure_return_type;
2165 }
2166
2167 pub struct #logger_type_name;
2168 impl #closure_type_name for #logger_type_name {
2169 fn #handle_method_name(&mut self, #(#closure_args_in_logger),*) -> #closure_return_type {
2170 log::info!("{}({}\n)",
2171 stringify!(#handle_method_name),
2172 [#(#log_field_names),*].join(", "),
2173 );
2174 #logger_return_type
2175 }
2176 }
2177
2178 unsafe impl Send for #logger_type_name {}
2179 unsafe impl Sync for #logger_type_name {}
2180
2181 impl<F: FnMut(#(#fn_mut_args),*) -> #closure_return_type> #closure_type_name for F {
2184 #[inline]
2185 fn #handle_method_name(&mut self, #(#closure_args),*) -> #closure_return_type {
2186 self(#(#wrapper_closure_args),*)
2187 }
2188 }
2189
2190 impl<T: #closure_type_name> #closure_type_name for Handler<T> {
2193 #[inline]
2194 fn #handle_method_name(&mut self, #(#closure_args),*) -> #closure_return_type {
2195 let inner = unsafe { &mut *self.inner.get() };
2196 inner.#handle_method_name(#(#wrapper_closure_args),*)
2197 }
2198 }
2199
2200 impl #closure_type_name for NoHandler {
2205 fn #handle_method_name(&mut self, #(#closure_args),*) -> #closure_return_type {
2206 unreachable!("NoHandler is a None sentinel; its callback must never be invoked")
2207 }
2208 }
2209
2210 #[allow(dead_code)]
2212 #(#doc_comments)*
2213 unsafe extern "C" fn #fn_name<F: #closure_type_name>(
2214 #(#args),*
2215 ) -> #closure_return_type
2216 {
2217 #[cfg(debug_assertions)]
2218 if #closure_name.is_null() {
2219 unimplemented!("closure should not be null")
2220 }
2221 #[cfg(feature = "extra-logging")]
2222 {
2223 log::debug!("calling {}", stringify!(#handle_method_name));
2224 }
2225 #[cfg(feature = "log-c-bindings")]
2226 log::debug!(
2227 "{}({}\n)",
2228 stringify!(#fn_name),
2229 [#(#arg_names_for_logging),*].join(", ")
2230 );
2231 let closure: &mut F = unsafe { &mut *(#closure_name as *mut F) };
2232 closure.#handle_method_name(#(#converted_args),*)
2233 }
2234
2235 #[allow(dead_code)]
2237 #(#doc_comments)*
2238 unsafe extern "C" fn #closure_fn_name<F: FnMut(#(#fn_mut_args),*) -> #closure_return_type>(
2239 #(#args),*
2240 ) -> #closure_return_type
2241 {
2242 #[cfg(debug_assertions)]
2243 if #closure_name.is_null() {
2244 unimplemented!("closure should not be null")
2245 }
2246 #[cfg(feature = "extra-logging")]
2247 {
2248 log::debug!("calling {}", stringify!(#closure_fn_name));
2249 }
2250 #[cfg(feature = "log-c-bindings")]
2251 log::debug!(
2252 "{}({}\n)",
2253 stringify!(#closure_fn_name),
2254 [#(#arg_names_for_logging),*].join(", ")
2255 );
2256 let closure: &mut F = unsafe { &mut *(#closure_name as *mut F) };
2257 closure(#(#converted_args),*)
2258 }
2259
2260 }
2261}
2262
2263pub fn generate_rust_code(
2264 wrapper: &CWrapper,
2265 wrappers: &BTreeMap<String, CWrapper>,
2266 include_common_code: bool,
2267 include_clippy: bool,
2268 include_aeron_client_registering_resource_t: bool,
2269 closure_handlers: &Vec<CHandler>,
2270) -> TokenStream {
2271 let class_name = Ident::new(&wrapper.class_name, proc_macro2::Span::call_site());
2272 let type_name = Ident::new(&wrapper.type_name, proc_macro2::Span::call_site());
2273
2274 let mut additional_outer_impls = vec![];
2275 let mut debug_fields = vec![];
2276
2277 let methods = wrapper.generate_methods(
2278 wrappers,
2279 closure_handlers,
2280 &mut additional_outer_impls,
2281 &mut debug_fields,
2282 );
2283 let tests = wrapper.generate_allocation_test();
2284 let mut constructor_fields = vec![];
2285 let mut new_ref_set_none = vec![];
2286 let constructor = wrapper.generate_constructor(wrappers, &mut constructor_fields, &mut new_ref_set_none);
2287
2288 let async_impls = if wrapper.type_name.starts_with("aeron_async_")
2289 || wrapper.type_name.starts_with("aeron_archive_async_")
2290 {
2291 let new_method = wrapper.methods.iter().find(|m| m.fn_name == wrapper.without_name);
2292
2293 if let Some(new_method) = new_method {
2294 let main_type = &wrapper.type_name.replace("_async_", "_").replace("_add_", "_");
2295 let main = get_possible_wrappers(main_type)
2296 .iter()
2297 .filter_map(|f| wrappers.get(f))
2298 .next()
2299 .expect(&format!("failed to find main type {}", main_type));
2300
2301 let poll_method = main
2302 .methods
2303 .iter()
2304 .find(|m| m.fn_name == format!("{}_poll", wrapper.without_name))
2305 .unwrap();
2306
2307 let main_class_name = format_ident!("{}", main.class_name);
2308 let async_class_name = format_ident!("{}", wrapper.class_name);
2309 let poll_method_name = format_ident!("{}_poll", wrapper.without_name);
2310 let new_method_name = format_ident!("{}", new_method.fn_name);
2311
2312 let client_class = wrappers
2313 .get(
2314 new_method
2315 .arguments
2316 .iter()
2317 .skip(1)
2318 .next()
2319 .unwrap()
2320 .c_type
2321 .split_whitespace()
2322 .last()
2323 .unwrap(),
2324 )
2325 .unwrap();
2326 let client_type = format_ident!("{}", client_class.class_name);
2327 let client_type_method_name = format_ident!(
2328 "{}",
2329 new_method
2330 .fn_name
2331 .replace(&format!("{}_", client_class.without_name), "")
2332 );
2333 let client_type_method_name_without_async = format_ident!(
2334 "{}",
2335 new_method
2336 .fn_name
2337 .replace(&format!("{}_", client_class.without_name), "")
2338 .replace("async_", "")
2339 );
2340
2341 let init_args: Vec<TokenStream> = poll_method
2342 .arguments
2343 .iter()
2344 .enumerate()
2345 .filter_map(|(idx, arg)| {
2346 if idx == 0 {
2347 Some(quote! { ctx_field })
2348 } else {
2349 let arg_name = arg.as_ident();
2350 let arg_name = ReturnType::new(arg.clone(), wrappers.clone())
2351 .handle_rs_to_c_return(quote! { #arg_name }, false);
2352 Some(quote! { #arg_name })
2353 }
2354 })
2355 .filter(|t| !t.is_empty())
2356 .collect();
2357
2358 let new_args: Vec<TokenStream> = poll_method
2359 .arguments
2360 .iter()
2361 .enumerate()
2362 .filter_map(|(idx, arg)| {
2363 if idx == 0 {
2364 None
2365 } else {
2366 let arg_name = arg.as_ident();
2367 let arg_type = ReturnType::new(arg.clone(), wrappers.clone()).get_new_return_type(false, true);
2368 if arg_type.clone().into_token_stream().is_empty() {
2369 None
2370 } else {
2371 Some(quote! { #arg_name: #arg_type })
2372 }
2373 }
2374 })
2375 .filter(|t| !t.is_empty())
2376 .collect();
2377
2378 let async_init_args: Vec<TokenStream> = new_method
2379 .arguments
2380 .iter()
2381 .enumerate()
2382 .filter_map(|(idx, arg)| {
2383 if idx == 0 {
2384 Some(quote! { ctx_field })
2385 } else {
2386 let arg_name = arg.as_ident();
2387 let arg_name = ReturnType::new(arg.clone(), wrappers.clone())
2388 .handle_rs_to_c_return(quote! { #arg_name }, false);
2389 Some(quote! { #arg_name })
2390 }
2391 })
2392 .filter(|t| !t.is_empty())
2393 .collect();
2394
2395 let async_log_expr_tokens = CWrapper::generate_arg_logging(&new_method.arguments, &async_init_args);
2397
2398 let generic_types: Vec<TokenStream> = new_method
2399 .arguments
2400 .iter()
2401 .flat_map(|arg| {
2402 ReturnType::new(arg.clone(), wrappers.clone())
2403 .method_generics_for_where(true)
2404 .into_iter()
2405 })
2406 .collect_vec();
2407 let where_clause_async = if generic_types.is_empty() {
2408 quote! {}
2409 } else {
2410 quote! { <#(#generic_types),*> }
2411 };
2412 let generic_types: Vec<TokenStream> = poll_method
2413 .arguments
2414 .iter()
2415 .flat_map(|arg| {
2416 ReturnType::new(arg.clone(), wrappers.clone())
2417 .method_generics_for_where(true)
2418 .into_iter()
2419 })
2420 .collect_vec();
2421 let where_clause_main = if generic_types.is_empty() {
2422 quote! {}
2423 } else {
2424 quote! { <#(#generic_types),*> }
2425 };
2426 let async_new_args: Vec<TokenStream> = new_method
2427 .arguments
2428 .iter()
2429 .enumerate()
2430 .filter_map(|(idx, arg)| {
2431 if idx == 0 {
2432 None
2433 } else {
2434 let arg_name = arg.as_ident();
2435 let arg_type = ReturnType::new(arg.clone(), wrappers.clone()).get_new_return_type(false, true);
2436 if arg_type.clone().into_token_stream().is_empty() {
2437 None
2438 } else {
2439 Some(quote! { #arg_name: #arg_type })
2440 }
2441 }
2442 })
2443 .filter(|t| !t.is_empty())
2444 .collect();
2445
2446 let async_dependancies = async_new_args
2447 .iter()
2448 .filter(|a| a.to_string().contains(" : Aeron") || a.to_string().contains(" : & Aeron"))
2449 .map(|e| {
2450 let var_name = format_ident!("{}", e.to_string().split_whitespace().next().unwrap());
2451 quote! {
2452 result.inner.add_dependency(#var_name.clone());
2453 }
2454 })
2455 .collect_vec();
2456
2457 let mut async_handler_deps: Vec<TokenStream> =
2458 CWrapper::handler_dependency_registrations(&new_method.arguments);
2459
2460 if let Some(client_arg) = async_new_args
2465 .iter()
2466 .find(|a| a.to_string().contains(" : Aeron") || a.to_string().contains(" : & Aeron"))
2467 {
2468 let client_var = format_ident!("{}", client_arg.to_string().split_whitespace().next().unwrap());
2469 let client_anchored: Vec<TokenStream> = new_method
2470 .arguments
2471 .iter()
2472 .filter_map(|arg| {
2473 if let ArgProcessing::Handler(_) = &arg.processing {
2474 if !arg.is_mut_pointer() {
2475 let name = arg.as_ident();
2476 return Some(quote! {
2477 if let Some(__handler) = #name {
2478 if let Some(__client_inner) = #client_var.inner.as_owned() {
2479 __client_inner.add_dependency(__handler.clone());
2480 }
2481 }
2482 });
2483 }
2484 }
2485 None
2486 })
2487 .collect();
2488 async_handler_deps.extend(client_anchored);
2489 }
2490
2491 let async_new_args_for_client = async_new_args.iter().skip(1).cloned().collect_vec();
2492
2493 let async_new_args_name_only: Vec<TokenStream> = new_method
2494 .arguments
2495 .iter()
2496 .enumerate()
2497 .filter_map(|(idx, arg)| {
2498 if idx < 2 {
2499 None
2500 } else {
2501 let arg_name = arg.as_ident();
2502 let arg_type = ReturnType::new(arg.clone(), wrappers.clone()).get_new_return_type(false, false);
2503 if arg_type.clone().into_token_stream().is_empty() {
2504 None
2505 } else {
2506 Some(quote! { #arg_name })
2507 }
2508 }
2509 })
2510 .filter(|t| !t.is_empty())
2511 .collect();
2512
2513 let poll_log_expr_tokens = CWrapper::generate_arg_logging(&poll_method.arguments, &init_args);
2515
2516 let close_cleanup = if let Some(close_method) = main.get_close_method() {
2517 let close_fn = format_ident!("{}", close_method.fn_name);
2518 let extra_args: Vec<TokenStream> = close_method
2523 .arguments
2524 .iter()
2525 .skip(1)
2526 .map(|_| quote! { Default::default() })
2527 .collect();
2528 quote! {
2529 Some(Box::new(move |ptr| unsafe {
2530 #close_fn(*ptr, #(#extra_args),*)
2531 }))
2532 }
2533 } else {
2534 quote! { None }
2535 };
2536
2537 quote! {
2538 impl #main_class_name {
2539 #[inline]
2540 pub fn new #where_clause_main (#(#new_args),*) -> Result<Self, AeronCError> {
2541 let resource = ManagedCResource::new(
2542 move |ctx_field| unsafe {
2543 #[cfg(feature = "log-c-bindings")]
2544 {
2545 let log_args = #poll_log_expr_tokens;
2546 log::info!("{}({})", stringify!(#poll_method_name), log_args);
2547 }
2548 #poll_method_name(#(#init_args),*)
2549 },
2550 #close_cleanup,
2551 false,
2552 )?;
2553 Ok(Self {
2554 inner: CResource::OwnedOnHeap(RcOrArc::new(resource)),
2555 })
2556 }
2557 }
2558
2559 impl #client_type {
2560 #[inline]
2561 pub fn #client_type_method_name #where_clause_async(&self, #(#async_new_args_for_client),*) -> Result<#async_class_name, AeronCError> {
2562 let mut result = #async_class_name::new(self, #(#async_new_args_name_only),*);
2563 if let Ok(result) = &mut result {
2564 result.inner.add_dependency(self.clone());
2565 }
2566
2567 result
2568 }
2569 }
2570
2571 impl #client_type {
2572 #[doc = r"Blocking convenience wrapper around the async add operation."]
2573 #[doc = r""]
2574 #[doc = r"**Convenience for examples and tests only.** It blocks the calling thread"]
2575 #[doc = r"in a busy-poll loop until the resource is available or `timeout` elapses. In"]
2576 #[doc = r"production, prefer the `async_add_*` variant and drive its `poll()` from your"]
2577 #[doc = r"own event loop rather than blocking on a single operation."]
2578 #[doc = r""]
2579 #[doc = r"# Production pattern (pseudo code)"]
2580 #[doc = r"```text"]
2581 #[doc = r"// Don't block — drive the async poller from your loop"]
2582 #[doc = r"let poller = client.async_add_*(...)?;"]
2583 #[doc = r"loop {"]
2584 #[doc = r" if let Some(resource) = poller.poll()? {"]
2585 #[doc = r" break; // ready"]
2586 #[doc = r" }"]
2587 #[doc = r" do_other_work(); // service other subscriptions, timers, etc."]
2588 #[doc = r"}"]
2589 #[doc = r"```"]
2590 #[doc = r""]
2591 #[doc = r"See `poll_blocking` on the async poller for the same caveat."]
2592 #[inline]
2593 pub fn #client_type_method_name_without_async #where_clause_async(&self #(
2594 , #async_new_args_for_client)*, timeout: std::time::Duration) -> Result<#main_class_name, AeronCError> {
2595 let start = std::time::Instant::now();
2596 loop {
2597 if let Ok(poller) = #async_class_name::new(self, #(#async_new_args_name_only),*) {
2598 while start.elapsed() <= timeout {
2599 if let Some(result) = poller.poll()? {
2600 return Ok(result);
2601 }
2602 #[cfg(debug_assertions)]
2603 std::thread::sleep(std::time::Duration::from_millis(10));
2604 }
2605 }
2606 if start.elapsed() > timeout {
2607 log::error!("failed async poll for {:?}", self);
2608 return Err(AeronErrorType::TimedOut.into());
2609 }
2610 #[cfg(debug_assertions)]
2611 std::thread::sleep(std::time::Duration::from_millis(10));
2612 }
2613 }
2614 }
2615
2616 impl #async_class_name {
2617 #[inline]
2618 pub fn new #where_clause_async (#(#async_new_args),*) -> Result<Self, AeronCError> {
2619 let resource_async = ManagedCResource::new(
2620 move |ctx_field| unsafe {
2621 #[cfg(feature = "log-c-bindings")]
2622 {
2623 let log_args = #async_log_expr_tokens;
2624 log::info!("{}({})", stringify!(#new_method_name), log_args);
2625 }
2626 #new_method_name(#(#async_init_args),*)
2627 },
2628 None,
2629 false,
2630 )?;
2631 let result = Self {
2632 inner: CResource::OwnedOnHeap(RcOrArc::new(resource_async)),
2633 };
2634 #(#async_dependancies)*
2635 #(#async_handler_deps)*
2640 Ok(result)
2641 }
2642
2643 #[inline]
2644 pub fn poll(&self) -> Result<Option<#main_class_name>, AeronCError> {
2645
2646 if let Some(inner) = self.inner.as_owned() {
2647 if inner.is_resource_released() {
2648 return Ok(None);
2649 }
2650 }
2651
2652 let mut result = #main_class_name::new(self);
2653 if let Ok(result) = &mut result {
2654 unsafe {
2655 #[cfg(feature = "multi-threaded")]
2656 for d in (&mut *self.inner.as_owned().unwrap().dependencies.lock().unwrap()).iter_mut() {
2657 result.inner.add_dependency(d.clone());
2658 }
2659 #[cfg(not(feature = "multi-threaded"))]
2660 for d in (&mut *self.inner.as_owned().unwrap().dependencies.get()).iter_mut() {
2661 result.inner.add_dependency(d.clone());
2662 }
2663 }
2664 }
2665
2666 match result {
2667 Ok(result) => {
2668 if let Some(inner) = self.inner.as_owned() {
2669 inner.mark_resource_released();
2670 }
2671 Ok(Some(result))
2672 }
2673 Err(e) if e.code == 0 => {
2674 Ok(None) }
2676 Err(e) => {
2677 if let Some(inner) = self.inner.as_owned() {
2678 inner.mark_resource_released();
2679 }
2680 Err(e)
2681 }
2682 }
2683 }
2684
2685 #[doc = r"Polls synchronously until the async operation completes or `timeout` elapses."]
2686 #[doc = r""]
2687 #[doc = r"**Convenience for examples and tests only.** It blocks the calling thread"]
2688 #[doc = r"in a busy-poll loop. In production, drive `poll()` from your own event loop"]
2689 #[doc = r"(between other work, on a timer, or in a dedicated duty cycle) rather than"]
2690 #[doc = r"blocking on a single operation."]
2691 #[doc = r""]
2692 #[doc = r"# Production pattern (pseudo code)"]
2693 #[doc = r"```text"]
2694 #[doc = r"// Don't block — integrate poll() into your existing loop"]
2695 #[doc = r"loop {"]
2696 #[doc = r" if let Some(resource) = poller.poll()? {"]
2697 #[doc = r" break; // ready"]
2698 #[doc = r" }"]
2699 #[doc = r" do_other_work(); // service other subscriptions, timers, etc."]
2700 #[doc = r"}"]
2701 #[doc = r"```"]
2702 #[doc = r""]
2703 #[doc = r"See the blocking `add_*(.., timeout)` helpers for the same caveat."]
2704 #[inline]
2705 pub fn poll_blocking(&self, timeout: std::time::Duration) -> Result<#main_class_name, AeronCError> {
2706 if let Some(result) = self.poll()? {
2707 return Ok(result);
2708 }
2709
2710 let time = std::time::Instant::now();
2711 while time.elapsed() < timeout {
2712 if let Some(result) = self.poll()? {
2713 return Ok(result);
2714 }
2715 #[cfg(debug_assertions)]
2716 std::thread::sleep(std::time::Duration::from_millis(10));
2717 }
2718 log::error!("failed async poll for {:?}", self);
2719 Err(AeronErrorType::TimedOut.into())
2720 }
2721 }
2722 }
2723 } else {
2724 quote! {}
2725 }
2726 } else {
2727 quote! {}
2728 };
2729
2730 let mut additional_impls = vec![];
2731
2732 if let Some(close_method) = wrapper.get_close_method() {
2733 let close_deferred_if_shared = wrapper.type_name == "aeron_t" || wrapper.type_name == "aeron_archive_t";
2734 let skip_generated_close =
2735 wrapper.methods.iter().any(|m| m.fn_name.contains("_init")) && !close_deferred_if_shared;
2736 if !skip_generated_close {
2737 let close_fn = format_ident!("{}", close_method.fn_name);
2738 let close_resource_call = if close_deferred_if_shared {
2739 quote! { self.inner.close_resource_deferred_if_shared() }
2740 } else {
2741 quote! { self.inner.close_resource() }
2742 };
2743 if close_deferred_if_shared {
2748 additional_impls.push(quote! {
2749 impl #class_name {
2750 pub fn close(self) -> Result<(), AeronCError> {
2758 let result = #close_resource_call;
2759 drop(self);
2761 result
2762 }
2763
2764 pub unsafe fn close_now(self) -> Result<(), AeronCError> {
2777 let result = self.inner.close_resource();
2778 drop(self);
2779 result
2780 }
2781 }
2782 });
2783 } else {
2784 additional_impls.push(quote! {
2785 impl #class_name {
2786 pub fn close(self) -> Result<(), AeronCError> {
2789 let result = #close_resource_call;
2790 drop(self);
2792 result
2793 }
2794 }
2795 });
2796 }
2797
2798 let close_has_notification_handler = !close_deferred_if_shared
2799 && close_method
2800 .arguments
2801 .iter()
2802 .any(|arg| matches!(arg.processing, ArgProcessing::Handler(_)))
2803 && close_method.arguments.iter().any(|arg| arg.is_c_void());
2804
2805 if close_has_notification_handler {
2806 additional_impls.push(quote! {
2807 impl #class_name {
2808 pub fn close_with_handler<AeronNotificationHandlerImpl: AeronNotificationCallback>(
2812 self,
2813 on_close_complete: Option<&Handler<AeronNotificationHandlerImpl>>,
2814 ) -> Result<(), AeronCError> {
2815 let result = self.inner.close_resource_with(move |ptr| unsafe {
2816 #close_fn(
2817 *ptr,
2818 {
2819 let callback: aeron_notification_t = if on_close_complete.is_none() {
2820 None
2821 } else {
2822 Some(aeron_notification_t_callback::<AeronNotificationHandlerImpl>)
2823 };
2824 callback
2825 },
2826 on_close_complete
2827 .map(|m| m.as_raw())
2828 .unwrap_or_else(|| std::ptr::null_mut()),
2829 )
2830 });
2831 drop(self);
2832 result
2833 }
2834 }
2835 });
2836 }
2837
2838 if wrapper.type_name == "aeron_counter_t" {
2840 additional_impls.push(quote! {
2841 impl #class_name {
2842 #[inline]
2843 pub fn addr_atomic(&self) -> &std::sync::atomic::AtomicI64 {
2844 unsafe { std::sync::atomic::AtomicI64::from_ptr(self.addr()) }
2845 }
2846 }
2847 });
2848 } else if wrapper.type_name == "aeron_publication_t" || wrapper.type_name == "aeron_exclusive_publication_t"
2849 {
2850 additional_impls.push(quote! {
2851 impl #class_name {
2852 #[inline]
2853 pub fn is_ready(&self) -> bool {
2854 self.is_connected() && self.position_limit() != 0
2855 }
2856 }
2857 });
2858 }
2859 }
2860 }
2861
2862 let common_code = if !include_common_code {
2863 quote! {}
2864 } else {
2865 TokenStream::from_str(COMMON_CODE).unwrap()
2866 };
2867 let warning_code = if !include_common_code {
2868 quote! {}
2869 } else {
2870 let mut code = String::new();
2871
2872 if include_clippy {
2873 code.push_str(
2874 " #![allow(non_upper_case_globals)]
2875 #![allow(non_camel_case_types)]
2876 #![allow(non_snake_case)]
2877 #![allow(clippy::all)]
2878 #![allow(unused_variables)]
2879 #![allow(unused_unsafe)]
2880",
2881 );
2882 }
2883
2884 if include_aeron_client_registering_resource_t {
2885 code.push_str(
2886 "
2887 type aeron_client_registering_resource_t = aeron_client_registering_resource_stct;
2888",
2889 );
2890 }
2891
2892 TokenStream::from_str(code.as_str()).unwrap()
2893 };
2894 let class_docs: Vec<TokenStream> = wrapper
2895 .docs
2896 .iter()
2897 .map(|doc| {
2898 quote! {
2899 #[doc = #doc]
2900 }
2901 })
2902 .collect();
2903
2904 let fields = wrapper.generate_fields(&wrappers, &mut debug_fields);
2905
2906 let default_impl =
2907 if wrapper.has_default_method() && !constructor.iter().map(|x| x.to_string()).join("").trim().is_empty() {
2908 quote! {
2919 impl Default for #class_name {
2921 fn default() -> Self {
2922 #class_name::new_zeroed_on_heap()
2923 }
2924 }
2925
2926 impl #class_name {
2927 pub fn clone_struct(&self) -> Self {
2936 let copy = Self::default();
2937 unsafe { copy.get_inner_mut().clone_from(self.deref()) };
2939 copy
2940 }
2941 }
2942 }
2943 } else {
2944 quote! {}
2945 };
2946
2947 quote! {
2948 #warning_code
2949
2950 #(#class_docs)*
2951 #[derive(Clone)]
2952 pub struct #class_name {
2953 inner: CResource<#type_name>,
2954 #(#constructor_fields)*
2955 }
2956
2957 impl core::fmt::Debug for #class_name {
2958 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2959 if self.inner.get().is_null() {
2960 f.debug_struct(stringify!(#class_name))
2961 .field("inner", &"null")
2962 .finish()
2963 } else {
2964 f.debug_struct(stringify!(#class_name))
2965 .field("inner", &self.inner)
2966 #(#debug_fields)*
2967 .finish()
2968 }
2969 }
2970 }
2971
2972 impl #class_name {
2973 #(#constructor)*
2974 #(#fields)*
2975 #(#methods)*
2976
2977 #[inline(always)]
2978 pub fn get_inner(&self) -> *mut #type_name {
2979 self.inner.get()
2980 }
2981
2982 #[inline(always)]
2990 pub unsafe fn get_inner_mut(&self) -> &mut #type_name {
2991 &mut *self.inner.get()
2992 }
2993
2994 #[inline(always)]
2995 pub fn get_inner_ref(&self) -> & #type_name {
2996 unsafe { &*self.inner.get() }
2997 }
2998 }
2999
3000 impl std::ops::Deref for #class_name {
3001 type Target = #type_name;
3002
3003 fn deref(&self) -> &Self::Target {
3004 self.get_inner_ref()
3005 }
3006 }
3007
3008 impl From<*mut #type_name> for #class_name {
3009 #[inline]
3010 fn from(value: *mut #type_name) -> Self {
3011 #class_name {
3012 inner: CResource::Borrowed(value),
3013 #(#new_ref_set_none)*
3014 }
3015 }
3016 }
3017
3018 impl From<#class_name> for *mut #type_name {
3019 #[inline]
3020 fn from(value: #class_name) -> Self {
3021 value.get_inner()
3022 }
3023 }
3024
3025 impl From<&#class_name> for *mut #type_name {
3026 #[inline]
3027 fn from(value: &#class_name) -> Self {
3028 value.get_inner()
3029 }
3030 }
3031
3032 impl From<#class_name> for #type_name {
3033 #[inline]
3034 fn from(value: #class_name) -> Self {
3035 unsafe { *value.get_inner().clone() }
3036 }
3037 }
3038
3039 impl From<*const #type_name> for #class_name {
3040 #[inline]
3041 fn from(value: *const #type_name) -> Self {
3042 #class_name {
3043 inner: CResource::Borrowed(value as *mut #type_name),
3044 #(#new_ref_set_none)*
3045 }
3046 }
3047 }
3048
3049 impl From<#type_name> for #class_name {
3050 #[inline]
3051 fn from(value: #type_name) -> Self {
3052 #class_name {
3053 inner: CResource::OwnedOnStack(MaybeUninit::new(value)),
3054 #(#new_ref_set_none)*
3055 }
3056 }
3057 }
3058
3059 #(#additional_impls)*
3060
3061 #async_impls
3062 #default_impl
3063 #tests
3064 #common_code
3065 }
3066}