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