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 possible_self = if uses_self {
614 quote! { &self, }
615 } else {
616 if return_type.to_string().eq("& str") {
617 return_type = quote! { &'static str };
618 }
619 quote! {}
620 };
621
622
623 let method_docs: Vec<TokenStream> = get_docs(&method.docs, wrappers, Some(&fn_arguments) );
624
625 let mut additional_methods = vec![];
626
627 Self::add_mut_string_methods_if_applicable(method, &fn_name, uses_self, &method_docs, &mut additional_methods);
628
629 Self::add_getter_instead_of_mut_arg_if_applicable(wrappers, method, &fn_name, &where_clause, &possible_self, &method_docs, &mut additional_methods);
631
632 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);
633
634 let mut_primitivies = method.arguments.iter()
635 .filter(|a| a.is_mut_pointer() && a.is_primitive())
636 .collect_vec();
637 let single_mut_field = method.return_type.is_c_raw_int() && mut_primitivies.len() == 1;
638
639 if single_mut_field {
642 let mut_field = mut_primitivies.first().unwrap();
643 let rt: Type = parse_str(mut_field.c_type.split_whitespace().last().unwrap()).unwrap();
644 let return_type = quote! { Result<#rt, AeronCError> };
645
646 let fn_arguments= fn_arguments.into_iter().filter(|arg| {!arg.to_string().contains("& mut ")})
647 .collect_vec();
648
649 let idx = arg_names.iter().enumerate()
650 .filter(|(_, arg)| arg.to_string().ends_with("* mut _"))
651 .map(|(i, _)| i)
652 .next().unwrap();
653
654 arg_names[idx] = quote! { &mut mut_result };
655
656 let mut first = true;
657 let mut method_docs = method_docs.iter()
658 .filter(|d| !d.to_string().contains("# Return"))
659 .map(|d| {
660 let mut string = d.to_string();
661 string = string.replace("# Parameters", "");
662 if string.contains("out param") {
663 TokenStream::from_str(&string.replace("- `", "\n# Return\n`")).unwrap()
664 } else {
665 if string.contains("- `") && first {
666 first = false;
667 string = string.replacen("- `","# Parameters\n- `", 1);
668 }
669 TokenStream::from_str(&string).unwrap()
670 }
671 })
672 .collect_vec();
673
674 let filter_param_title = !method_docs.iter().any(|d| d.to_string().contains("- `"));
675
676 if filter_param_title {
677 method_docs = method_docs.into_iter()
678 .map(|s| TokenStream::from_str(s.to_string().replace("# Parameters\n", "").as_str()).unwrap())
679 .collect_vec();
680 }
681
682 quote! {
683 #[inline]
684 #(#method_docs)*
685 pub fn #fn_name #where_clause(#possible_self #(#fn_arguments),*) -> #return_type {
686 #set_closed
687 unsafe {
688 let mut mut_result: #rt = Default::default();
689 let err_code = #ffi_call(#(#arg_names),*);
690
691 if err_code < 0 {
692 return Err(AeronCError::from_code(err_code));
693 } else {
694 return Ok(mut_result);
695 }
696 }
697 }
698
699 #(#additional_methods)*
700 }
701 } else {
702 quote! {
703 #[inline]
704 #(#method_docs)*
705 pub fn #fn_name #where_clause(#possible_self #(#fn_arguments),*) -> #return_type {
706 #set_closed
707 unsafe {
708 let result = #ffi_call(#(#arg_names),*);
709 #converter
710 }
711 }
712
713 #(#additional_methods)*
714 }
715 }
716 })
717 .collect()
718 }
719
720 fn add_once_methods_for_handlers(
721 closure_handlers: &Vec<CHandler>,
722 method: &Method,
723 fn_name: &Ident,
724 return_type: &TokenStream,
725 ffi_call: &Ident,
726 where_clause: &TokenStream,
727 fn_arguments: &Vec<TokenStream>,
728 arg_names: &mut Vec<TokenStream>,
729 converter: &TokenStream,
730 possible_self: &TokenStream,
731 method_docs: &Vec<TokenStream>,
732 additional_methods: &mut Vec<TokenStream>,
733 set_closed: &TokenStream,
734 ) {
735 if method.arguments.iter().any(|arg| {
736 matches!(arg.processing, ArgProcessing::Handler(_))
737 && !method.fn_name.starts_with("set_")
738 && !method.fn_name.starts_with("add_")
739 }) {
740 let fn_name = format_ident!("{}_once", fn_name);
741
742 let mut where_clause = where_clause.to_string();
744
745 for c in closure_handlers.iter() {
746 if !c.closure_type_name.is_empty() {
747 where_clause = where_clause.replace(
748 &c.closure_type_name.to_string(),
749 &c.fn_mut_signature.to_string(),
750 );
751 }
752 }
753 let where_clause = parse_str::<TokenStream>(&where_clause).unwrap();
754
755 let fn_arguments = fn_arguments.iter().map(|arg| {
757 let mut arg = arg.clone();
758 let str = arg.to_string();
759 if str.contains("& Handler ") {
760 let parts = str.split(" ").collect_vec();
762 let variable_name = parse_str::<TokenStream>(parts[0]).unwrap();
763 let closure_type = parse_str::<TokenStream>(parts[parts.len() - 2]).unwrap();
764 arg = quote! { mut #variable_name : #closure_type };
765 }
766
767 arg
768 });
769
770 let arg_names = arg_names.iter().map(|x| {
772 let mut str = x.to_string()
773 .replace("_callback :: <", "_callback_for_once_closure :: <")
774 ;
775
776 if str.contains("_callback_for_once_closure") {
777 let caps = regex::Regex::new(
794 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*\).*"#
795 )
796 .unwrap()
797 .captures(&str)
798 .expect(&format!("regex failed for {str}"));
799 let func_type = parse_str::<TokenStream>(&caps["type"]).unwrap();
800 let handler_var_name = parse_str::<TokenStream>(&caps["handler_var_name"]).unwrap();
801 let callback = parse_str::<TokenStream>(&caps["callback"]).unwrap();
802 let handler_type = parse_str::<TokenStream>(&caps["handler"]).unwrap();
803
804 let new_code = quote! {
805 Some(#callback::<#handler_type>),
806 &mut #handler_var_name as *mut _ as *mut std::os::raw::c_void
807 };
808 str = new_code.to_string();
809 }
810
811 parse_str::<TokenStream>(&str).unwrap()
812 }).collect_vec();
813 additional_methods.push(quote! {
814 #[inline]
815 #(#method_docs)*
816 pub fn #fn_name #where_clause(#possible_self #(#fn_arguments),*) -> #return_type {
821 #set_closed
822 unsafe {
823 let result = #ffi_call(#(#arg_names),*);
824 #converter
825 }
826 }
827 })
828 }
829 }
830
831 fn add_getter_instead_of_mut_arg_if_applicable(
832 wrappers: &BTreeMap<String, CWrapper>,
833 method: &Method,
834 fn_name: &Ident,
835 where_clause: &TokenStream,
836 possible_self: &TokenStream,
837 method_docs: &Vec<TokenStream>,
838 additional_methods: &mut Vec<TokenStream>,
839 ) {
840 if ["constants", "buffers", "values"]
841 .iter()
842 .any(|name| method.struct_method_name == *name)
843 && method.arguments.len() == 2
844 {
845 let rt = ReturnType::new(method.arguments[1].clone(), wrappers.clone());
846 let return_type = rt.get_new_return_type(false, false);
847 let getter_method = format_ident!("get_{}", fn_name);
848 let method_docs = method_docs
849 .iter()
850 .cloned()
851 .take_while(|t| !t.to_string().contains(" Parameter"))
852 .collect_vec();
853 additional_methods.push(quote! {
854 #[inline]
855 #(#method_docs)*
856 pub fn #getter_method #where_clause(#possible_self) -> Result<#return_type, AeronCError> {
857 let result = #return_type::new_zeroed_on_stack();
858 self.#fn_name(&result)?;
859 Ok(result)
860 }
861 });
862 }
863 }
864
865 fn add_mut_string_methods_if_applicable(
866 method: &Method,
867 fn_name: &Ident,
868 uses_self: bool,
869 method_docs: &Vec<TokenStream>,
870 additional_methods: &mut Vec<TokenStream>,
871 ) {
872 if method.arguments.len() == 3 && uses_self {
873 let method_docs = method_docs.clone();
874 let into_method = format_ident!("{}_into", fn_name);
875 if method.arguments[1].is_mut_c_string() && method.arguments[2].is_usize() {
876 let string_method = format_ident!("{}_as_string", fn_name);
877 additional_methods.push(quote! {
878 #[inline]
879 #(#method_docs)*
880 pub fn #string_method(
881 &self,
882 max_length: usize,
883 ) -> Result<String, AeronCError> {
884 let mut result = String::with_capacity(max_length);
885 self.#into_method(&mut result)?;
886 Ok(result)
887 }
888
889 #[inline]
890 #(#method_docs)*
891 #[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"]
892 pub fn #into_method(
893 &self,
894 dst_truncate_to_capacity: &mut String,
895 ) -> Result<i32, AeronCError> {
896 unsafe {
897 let capacity = dst_truncate_to_capacity.capacity();
898 let vec = dst_truncate_to_capacity.as_mut_vec();
899 vec.set_len(capacity);
900 let result = self.#fn_name(vec.as_mut_ptr() as *mut _, capacity)?;
901 let mut len = 0;
902 loop {
903 if len == capacity {
904 break;
905 }
906 let val = vec[len];
907 if val == 0 {
908 break;
909 }
910 len += 1;
911 }
912 vec.set_len(len);
913 Ok(result)
914 }
915 }
916 });
917 }
918 }
919 }
920
921 fn generate_fields(
923 &self,
924 cwrappers: &BTreeMap<String, CWrapper>,
925 debug_fields: &mut Vec<TokenStream>,
926 ) -> Vec<TokenStream> {
927 self.fields
928 .iter()
929 .filter(|arg| {
930 !arg.name.starts_with("_")
931 && !self
932 .methods
933 .iter()
934 .any(|m| m.struct_method_name.as_str() == arg.name)
935 })
936 .map(|arg| {
937 let field_name = &arg.name;
938 let fn_name = Ident::new(field_name, proc_macro2::Span::call_site());
939
940 let mut arg = arg.clone();
941 if arg.is_mut_c_string() {
943 arg.c_type = arg.c_type.replace(" mut ", " const ");
944 }
945 let mut rt = ReturnType::new(arg.clone(), cwrappers.clone());
946 let mut return_type = rt.get_new_return_type(false, false);
947 let handler = if let ArgProcessing::Handler(_) = &arg.processing {
948 true
949 } else {
950 false
951 };
952 if return_type.is_empty() || handler {
953 rt = ReturnType::new(
954 Arg {
955 processing: ArgProcessing::Default,
956 ..arg.clone()
957 },
958 cwrappers.clone(),
959 );
960 return_type = rt.get_new_return_type(false, false);
961 }
962 let converter = rt.handle_c_to_rs_return(quote! { self.#fn_name }, false, true);
963
964 if rt.original.is_primitive()
965 || rt.original.is_c_string_any()
966 || rt.original.is_byte_array()
967 || cwrappers.contains_key(&rt.original.c_type)
968 {
969 if !rt.original.is_any_pointer() {
970 debug_fields
971 .push(quote! { .field(stringify!(#fn_name), &self.#fn_name()) });
972 }
973 }
974
975 quote! {
976 #[inline]
977 pub fn #fn_name(&self) -> #return_type {
978 #converter
979 }
980 }
981 })
982 .filter(|t| !t.is_empty())
983 .collect()
984 }
985
986 fn generate_constructor(
988 &self,
989 wrappers: &BTreeMap<String, CWrapper>,
990 constructor_fields: &mut Vec<TokenStream>,
991 new_ref_set_none: &mut Vec<TokenStream>,
992 ) -> Vec<TokenStream> {
993 let constructors = self
994 .methods
995 .iter()
996 .filter(|m| m.arguments.iter().any(|arg| arg.is_double_mut_pointer() ))
997 .map(|method| {
998 let init_fn = format_ident!("{}", method.fn_name);
999 let close_method = self.find_close_method(method);
1000 let found_close = close_method.is_some()
1001 && close_method.unwrap().return_type.is_c_raw_int()
1002 && close_method.unwrap() != method
1003 && close_method
1004 .unwrap()
1005 .arguments
1006 .iter()
1007 .skip(1)
1008 .all(|a| method.arguments.iter().any(|a2| a.name == a2.name));
1009 if found_close {
1010 let close_fn = format_ident!("{}", close_method.unwrap().fn_name);
1011 let init_args: Vec<TokenStream> = method
1012 .arguments
1013 .iter()
1014 .enumerate()
1015 .map(|(idx, arg)| {
1016 if idx == 0 {
1017 quote! { ctx_field }
1018 } else {
1019 let arg_name = arg.as_ident();
1020 quote! { #arg_name }
1021 }
1022 })
1023 .filter(|t| !t.is_empty())
1024 .collect();
1025 let close_args: Vec<TokenStream> = close_method
1026 .unwrap_or(method)
1027 .arguments
1028 .iter()
1029 .enumerate()
1030 .map(|(idx, arg)| {
1031 if idx == 0 {
1032 if arg.is_double_mut_pointer() {
1033 quote! { ctx_field }
1034 } else {
1035 quote! { *ctx_field }
1036 }
1037 } else {
1038 let arg_name = arg.as_ident();
1039 quote! { #arg_name.into() }
1040 }
1041 })
1042 .filter(|t| !t.is_empty())
1043 .collect();
1044 let lets: Vec<TokenStream> =
1045 Self::lets_for_copying_arguments(wrappers, &method.arguments, true);
1046
1047 constructor_fields.clear();
1048 constructor_fields.extend(Self::constructor_fields(
1049 wrappers,
1050 &method.arguments,
1051 &self.class_name,
1052 ));
1053
1054 let new_ref_args =
1055 Self::new_args(wrappers, &method.arguments, &self.class_name, false);
1056
1057 new_ref_set_none.clear();
1058 new_ref_set_none.extend(Self::new_args(
1059 wrappers,
1060 &method.arguments,
1061 &self.class_name,
1062 true,
1063 ));
1064
1065 let new_args: Vec<TokenStream> = method
1066 .arguments
1067 .iter()
1068 .enumerate()
1069 .filter_map(|(_idx, arg)| {
1070 if arg.is_double_mut_pointer() {
1071 None
1072 } else {
1073 let arg_name = arg.as_ident();
1074 let arg_type = ReturnType::new(arg.clone(), wrappers.clone())
1075 .get_new_return_type(false, true);
1076 if arg_type.clone().into_token_stream().is_empty() {
1077 None
1078 } else {
1079 Some(quote! { #arg_name: #arg_type })
1080 }
1081 }
1082 })
1083 .filter(|t| !t.is_empty())
1084 .collect();
1085
1086 let fn_name = format_ident!(
1087 "{}",
1088 method
1089 .struct_method_name
1090 .replace("init", "new")
1091 .replace("create", "new")
1092 );
1093
1094 let generic_types: Vec<TokenStream> = method
1095 .arguments
1096 .iter()
1097 .flat_map(|arg| {
1098 ReturnType::new(arg.clone(), wrappers.clone())
1099 .method_generics_for_where()
1100 .into_iter()
1101 })
1102 .collect_vec();
1103 let where_clause = if generic_types.is_empty() {
1104 quote! {}
1105 } else {
1106 quote! { <#(#generic_types),*> }
1107 };
1108
1109 let method_docs: Vec<TokenStream> =
1110 get_docs(&method.docs, wrappers, Some(&new_args));
1111
1112 let is_closed_method = self.get_is_closed_method_quote();
1113 quote! {
1114 #(#method_docs)*
1115 pub fn #fn_name #where_clause(#(#new_args),*) -> Result<Self, AeronCError> {
1116 #(#lets)*
1117 let resource_constructor = ManagedCResource::new(
1119 move |ctx_field| unsafe { #init_fn(#(#init_args),*) },
1120 Some(Box::new(move |ctx_field| unsafe { #close_fn(#(#close_args),*)} )),
1121 false,
1122 #is_closed_method,
1123 )?;
1124
1125 Ok(Self {
1126 inner: CResource::OwnedOnHeap(std::rc::Rc::new(resource_constructor)),
1127 #(#new_ref_args)*
1128 })
1129 }
1130 }
1131 } else {
1132 quote! {}
1133 }
1134 })
1135 .collect_vec();
1136
1137 let no_constructor = constructors
1138 .iter()
1139 .map(|x| x.to_string())
1140 .join("")
1141 .trim()
1142 .is_empty();
1143 if no_constructor {
1144 let type_name = format_ident!("{}", self.type_name);
1145 let is_closed_method = self.get_is_closed_method_quote();
1146
1147 let zeroed_impl = quote! {
1148 #[inline]
1149 pub fn new_zeroed_on_heap() -> Self {
1151 let resource = ManagedCResource::new(
1152 move |ctx_field| {
1153 #[cfg(feature = "extra-logging")]
1154 log::info!("creating zeroed empty resource on heap {}", stringify!(#type_name));
1155 let inst: #type_name = unsafe { std::mem::zeroed() };
1156 let inner_ptr: *mut #type_name = Box::into_raw(Box::new(inst));
1157 unsafe { *ctx_field = inner_ptr };
1158 0
1159 },
1160 None,
1161 true,
1162 #is_closed_method
1163 ).unwrap();
1164
1165 Self {
1166 inner: CResource::OwnedOnHeap(std::rc::Rc::new(resource)),
1167 }
1168 }
1169
1170 #[inline]
1171 pub fn new_zeroed_on_stack() -> Self {
1174 #[cfg(feature = "extra-logging")]
1175 log::debug!("creating zeroed empty resource on stack {}", stringify!(#type_name));
1176
1177 Self {
1178 inner: CResource::OwnedOnStack(std::mem::MaybeUninit::zeroed()),
1179 }
1180 }
1181 };
1182 if self.has_default_method() {
1183 let type_name = format_ident!("{}", self.type_name);
1184 let new_args: Vec<TokenStream> = self
1185 .fields
1186 .iter()
1187 .filter_map(|arg| {
1188 let arg_name = arg.as_ident();
1189 let arg_type = ReturnType::new(arg.clone(), wrappers.clone())
1190 .get_new_return_type(false, true);
1191 if arg_type.is_empty() {
1192 None
1193 } else {
1194 Some(quote! { #arg_name: #arg_type })
1195 }
1196 })
1197 .filter(|t| !t.is_empty())
1198 .collect();
1199 let init_args: Vec<TokenStream> = self
1200 .fields
1201 .iter()
1202 .map(|arg| {
1203 let arg_name = arg.as_ident();
1204 let value = ReturnType::new(arg.clone(), wrappers.clone())
1205 .handle_rs_to_c_return(quote! { #arg_name }, true);
1206 quote! { #value }
1207 })
1208 .filter(|t| !t.is_empty())
1209 .collect();
1210
1211 let generic_types: Vec<TokenStream> = self
1212 .fields
1213 .iter()
1214 .flat_map(|arg| {
1215 ReturnType::new(arg.clone(), wrappers.clone())
1216 .method_generics_for_where()
1217 .into_iter()
1218 })
1219 .collect_vec();
1220 let where_clause = if generic_types.is_empty() {
1221 quote! {}
1222 } else {
1223 quote! { <#(#generic_types),*> }
1224 };
1225
1226 let cloned_fields = self
1227 .fields
1228 .iter()
1229 .filter(|a| a.processing == ArgProcessing::Default)
1230 .cloned()
1231 .collect_vec();
1232 let lets: Vec<TokenStream> =
1233 Self::lets_for_copying_arguments(wrappers, &cloned_fields, false);
1234
1235 let is_closed_method = self.get_is_closed_method_quote();
1236
1237 vec![quote! {
1238 #[inline]
1239 pub fn new #where_clause(#(#new_args),*) -> Result<Self, AeronCError> {
1240 #(#lets)*
1241 let r_constructor = ManagedCResource::new(
1243 move |ctx_field| {
1244 let inst = #type_name { #(#init_args),* };
1245 let inner_ptr: *mut #type_name = Box::into_raw(Box::new(inst));
1246 unsafe { *ctx_field = inner_ptr };
1247 0
1248 },
1249 None,
1250 true,
1251 #is_closed_method
1252 )?;
1253
1254 Ok(Self {
1255 inner: CResource::OwnedOnHeap(std::rc::Rc::new(r_constructor)),
1256 })
1257 }
1258
1259 #zeroed_impl
1260 }]
1261 } else {
1262 vec![zeroed_impl]
1263 }
1264 } else {
1265 constructors
1266 }
1267 }
1268
1269 fn lets_for_copying_arguments(
1270 wrappers: &BTreeMap<String, CWrapper>,
1271 arguments: &Vec<Arg>,
1272 include_let_statements: bool,
1273 ) -> Vec<TokenStream> {
1274 arguments
1275 .iter()
1276 .enumerate()
1277 .filter_map(|(_idx, arg)| {
1278 if arg.is_double_mut_pointer() {
1279 None
1280 } else {
1281 let arg_name = arg.as_ident();
1282 let rtype = arg.as_type();
1283
1284 let fields = if arg.is_single_mut_pointer()
1286 && wrappers.contains_key(arg.c_type.split_whitespace().last().unwrap())
1287 {
1288 let arg_copy = format_ident!("{}_copy", arg.name);
1289 quote! {
1290 let #arg_copy = #arg_name.clone();
1291 }
1292 } else {
1293 quote! {}
1294 };
1295
1296 let return_type = ReturnType::new(arg.clone(), wrappers.clone());
1297
1298 if let ArgProcessing::StringWithLength(_args)
1299 | ArgProcessing::ByteArrayWithLength(_args) =
1300 &return_type.original.processing
1301 {
1302 return None;
1303 }
1304 if let ArgProcessing::Handler(args) = &return_type.original.processing {
1305 let arg1 = args[0].as_ident();
1306 let arg2 = args[1].as_ident();
1307 let value = return_type.handle_rs_to_c_return(quote! { #arg_name }, false);
1308
1309 if value.is_empty() {
1310 return None;
1311 }
1312
1313 if include_let_statements {
1314 return Some(quote! { #fields let (#arg1, #arg2)= (#value); });
1315 } else {
1316 return Some(fields);
1317 }
1318 }
1319
1320 let value = return_type.handle_rs_to_c_return(quote! { #arg_name }, false);
1321 if value.is_empty() {
1322 None
1323 } else {
1324 if include_let_statements {
1325 Some(quote! { #fields let #arg_name: #rtype = #value; })
1326 } else {
1327 return Some(fields);
1328 }
1329 }
1330 }
1331 })
1332 .filter(|t| !t.is_empty())
1333 .collect()
1334 }
1335
1336 fn constructor_fields(
1337 wrappers: &BTreeMap<String, CWrapper>,
1338 arguments: &Vec<Arg>,
1339 class_name: &String,
1340 ) -> Vec<TokenStream> {
1341 if class_name == "AeronAsyncDestination" {
1342 return vec![];
1343 }
1344
1345 arguments
1346 .iter()
1347 .enumerate()
1348 .filter_map(|(_idx, arg)| {
1349 if arg.is_double_mut_pointer() {
1350 None
1351 } else {
1352 let arg_name = arg.as_ident();
1353 let rtype = arg.as_type();
1354 if arg.is_single_mut_pointer()
1355 && wrappers.contains_key(arg.c_type.split_whitespace().last().unwrap())
1356 {
1357 let return_type = ReturnType::new(arg.clone(), wrappers.clone());
1358 let return_type = return_type.get_new_return_type(false, false);
1359
1360 let arg_copy = format_ident!("_{}", arg.name);
1361 Some(quote! {
1362 #arg_copy: Option<#return_type>,
1363 })
1364 } else {
1365 None
1366 }
1367 }
1368 })
1369 .collect()
1370 }
1371
1372 fn new_args(
1373 wrappers: &BTreeMap<String, CWrapper>,
1374 arguments: &Vec<Arg>,
1375 class_name: &String,
1376 set_none: bool,
1377 ) -> Vec<TokenStream> {
1378 if class_name == "AeronAsyncDestination" {
1379 return vec![];
1380 }
1381
1382 arguments
1383 .iter()
1384 .enumerate()
1385 .filter_map(|(_idx, arg)| {
1386 if arg.is_double_mut_pointer() {
1387 None
1388 } else {
1389 let arg_name = arg.as_ident();
1390 let rtype = arg.as_type();
1391 if arg.is_single_mut_pointer()
1392 && wrappers.contains_key(arg.c_type.split_whitespace().last().unwrap())
1393 {
1394 let arg_f = format_ident!("_{}", &arg.name);
1395 let arg_copy = format_ident!("{}_copy", &arg.name);
1396 if set_none {
1397 Some(quote! {
1398 #arg_f: None,
1399 })
1400 } else {
1401 Some(quote! {
1402 #arg_f: Some(#arg_copy),
1403 })
1404 }
1405 } else {
1406 None
1407 }
1408 }
1409 })
1410 .collect()
1411 }
1412
1413 fn find_close_method(&self, method: &Method) -> Option<&Method> {
1414 let mut close_method = None;
1415
1416 if ["_init", "_create", "_add"]
1418 .iter()
1419 .all(|find| !method.fn_name.contains(find))
1420 {
1421 return None;
1422 }
1423
1424 for name in ["_destroy", "_delete"] {
1425 let close_fn = format_ident!(
1426 "{}",
1427 method
1428 .fn_name
1429 .replace("_init", "_close")
1430 .replace("_create", name)
1431 .replace("_add_", "_remove_")
1432 );
1433 let method = self
1434 .methods
1435 .iter()
1436 .find(|m| close_fn.to_string().contains(&m.fn_name));
1437 if method.is_some() {
1438 close_method = method;
1439 break;
1440 }
1441 }
1442 close_method
1443 }
1444
1445 fn has_default_method(&self) -> bool {
1446 let no_init_method = !self.methods.iter().any(|m| {
1448 m.arguments.iter().any(|arg| {
1449 arg.is_double_mut_pointer()
1450 || (arg.is_single_mut_pointer() && m.fn_name.contains("_init_"))
1451 })
1452 });
1453
1454 no_init_method
1455 && !self.fields.iter().any(|arg| arg.name.starts_with("_"))
1456 && !self.fields.is_empty()
1457 }
1458}
1459
1460fn get_docs(
1461 docs: &BTreeSet<String>,
1462 wrappers: &BTreeMap<String, CWrapper>,
1463 arguments: Option<&Vec<TokenStream>>,
1464) -> Vec<TokenStream> {
1465 let mut first_param = true;
1466 docs.iter()
1467 .flat_map(|d| d.lines())
1468 .filter(|s| {
1469 arguments.is_none()
1470 || !s.contains("@param")
1471 || (s.contains("@param")
1472 && arguments.unwrap().iter().any(|a| {
1473 s.contains(
1474 format!(" {}", a.to_string().split_whitespace().next().unwrap())
1475 .as_str(),
1476 )
1477 }))
1478 })
1479 .map(|doc| {
1480 let mut doc = doc.to_string();
1481
1482 if first_param && doc.contains("@param") {
1483 doc = format!("# Parameters\n{}", doc);
1484 first_param = false;
1485 }
1486
1487 if doc.contains("@param") {
1488 doc = regex::Regex::new("@param\\s+([^ ]+)")
1489 .unwrap()
1490 .replace(doc.as_str(), "\n - `$1`")
1491 .to_string();
1492 }
1493
1494 doc = doc
1495 .replace("@return", "\n# Return\n")
1496 .replace("<p>", "\n")
1497 .replace("</p>", "\n");
1498
1499 doc = wrappers.values().fold(doc, |acc, v| {
1500 acc.replace(&v.type_name, &format!("`{}`", v.class_name))
1501 });
1502
1503 if doc.contains("@deprecated") {
1504 quote! {
1505 #[deprecated]
1506 #[doc = #doc]
1507 }
1508 } else {
1509 quote! {
1510 #[doc = #doc]
1511 }
1512 }
1513 })
1514 .collect()
1515}
1516
1517pub fn generate_handlers(handler: &mut CHandler, bindings: &CBinding) -> TokenStream {
1518 if handler
1519 .args
1520 .iter()
1521 .any(|arg| arg.is_primitive() && arg.is_mut_pointer())
1522 {
1523 return quote! {};
1524 }
1525
1526 let fn_name = format_ident!("{}_callback", handler.type_name);
1527 let closure_fn_name = format_ident!("{}_callback_for_once_closure", handler.type_name);
1528 let doc_comments: Vec<TokenStream> = handler
1529 .docs
1530 .iter()
1531 .flat_map(|doc| doc.lines())
1532 .map(|line| quote! { #[doc = #line] })
1533 .collect();
1534
1535 let closure = handler
1536 .args
1537 .iter()
1538 .find(|a| a.is_c_void())
1539 .unwrap()
1540 .name
1541 .clone();
1542 let closure_name = format_ident!("{}", closure);
1543 let closure_type_name = format_ident!("{}Callback", snake_to_pascal_case(&handler.type_name));
1544 let closure_return_type = handler.return_type.as_type();
1545
1546 let logger_type_name = format_ident!("{}Logger", snake_to_pascal_case(&handler.type_name));
1547
1548 let handle_method_name = format_ident!(
1549 "handle_{}",
1550 &handler.type_name[..handler.type_name.len() - 2]
1551 );
1552
1553 let no_method_name = format_ident!(
1554 "no_{}_handler",
1555 &handler.type_name[..handler.type_name.len() - 2]
1556 .replace("_on_", "_")
1557 .replace("aeron_", "")
1558 );
1559
1560 let args: Vec<TokenStream> = handler
1561 .args
1562 .iter()
1563 .map(|arg| {
1564 let arg_name = arg.as_ident();
1565 let arg_type: Type = arg.as_type();
1567 quote! { #arg_name: #arg_type }
1568 })
1569 .filter(|t| !t.is_empty())
1570 .collect();
1571
1572 let converted_args: Vec<TokenStream> = handler
1573 .args
1574 .iter()
1575 .filter_map(|arg| {
1576 let name = &arg.name;
1577 let arg_name = arg.as_ident();
1578 if name != &closure {
1579 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
1580 Some(return_type.handle_c_to_rs_return(quote! {#arg_name}, false, false))
1581 } else {
1582 None
1583 }
1584 })
1585 .filter(|t| !t.is_empty())
1586 .collect();
1587
1588 let closure_args: Vec<TokenStream> = handler
1589 .args
1590 .iter()
1591 .filter_map(|arg| {
1592 let name = &arg.name;
1593 if name == &closure {
1594 return None;
1595 }
1596
1597 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
1598 let type_name = return_type.get_new_return_type(false, false);
1599 let field_name = format_ident!("{}", name);
1600 if type_name.is_empty() {
1601 None
1602 } else {
1603 Some(quote! {
1604 #field_name: #type_name
1605 })
1606 }
1607 })
1608 .filter(|t| !t.is_empty())
1609 .collect();
1610
1611 let mut log_field_names = vec![];
1612 let closure_args_in_logger: Vec<TokenStream> = handler
1613 .args
1614 .iter()
1615 .filter_map(|arg| {
1616 let name = &arg.name;
1617 if name == &closure {
1618 return None;
1619 }
1620
1621 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
1622 let type_name = return_type.get_new_return_type(false, false);
1623 let field_name = format_ident!("{}", name);
1624 if type_name.is_empty() {
1625 None
1626 } else {
1627 log_field_names.push({
1628 Some(quote! { format!("{} : {:?}", stringify!(#field_name), #field_name) })
1629 });
1630
1631 Some(quote! {
1632 #field_name: #type_name
1633 })
1634 }
1635 })
1636 .filter(|t| !t.is_empty())
1637 .collect();
1638
1639 if log_field_names.is_empty() {
1640 log_field_names.push(Some(quote! { "" }));
1641 }
1642
1643 let fn_mut_args: Vec<TokenStream> = handler
1644 .args
1645 .iter()
1646 .filter_map(|arg| {
1647 let name = &arg.name;
1648 if name == &closure {
1649 return None;
1650 }
1651
1652 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone());
1653 let type_name = return_type.get_new_return_type(false, false);
1654 if arg.is_single_mut_pointer() && arg.is_primitive() {
1655 let owned_type: Type =
1656 parse_str(arg.c_type.split_whitespace().last().unwrap()).unwrap();
1657 return Some(quote! { #owned_type });
1658 } else {
1659 return Some(quote! {
1660 #type_name
1661 });
1662 }
1663 })
1664 .filter(|t| !t.is_empty())
1665 .collect();
1666
1667 handler.fn_mut_signature = quote! {
1668 FnMut(#(#fn_mut_args),*) -> #closure_return_type
1669 };
1670 handler.closure_type_name = quote! {
1671 #closure_type_name
1672 };
1673
1674 let logger_return_type = if closure_return_type.to_token_stream().to_string().eq("()") {
1675 closure_return_type.clone().to_token_stream()
1676 } else {
1677 quote! {
1678 unimplemented!()
1679 }
1680 };
1681
1682 let wrapper_closure_args: Vec<TokenStream> = handler
1683 .args
1684 .iter()
1685 .filter_map(|arg| {
1686 let name = &arg.name;
1687 if name == &closure {
1688 return None;
1689 }
1690
1691 let field_name = format_ident!("{}", name);
1692 let return_type = ReturnType::new(arg.clone(), bindings.wrappers.clone())
1693 .get_new_return_type(false, false);
1694 if return_type.is_empty() {
1695 None
1696 } else {
1697 Some(quote! { #field_name })
1698 }
1699 })
1700 .filter(|t| !t.is_empty())
1701 .collect();
1702
1703 quote! {
1704 #(#doc_comments)*
1705 pub trait #closure_type_name {
1709 fn #handle_method_name(&mut self, #(#closure_args),*) -> #closure_return_type;
1710 }
1711
1712 pub struct #logger_type_name;
1713 impl #closure_type_name for #logger_type_name {
1714 fn #handle_method_name(&mut self, #(#closure_args_in_logger),*) -> #closure_return_type {
1715 log::info!("{}(\n\t{}\n)",
1716 stringify!(#handle_method_name),
1717 [#(#log_field_names),*].join(",\n\t"),
1718 );
1719 #logger_return_type
1720 }
1721 }
1722
1723 unsafe impl Send for #logger_type_name {}
1724 unsafe impl Sync for #logger_type_name {}
1725
1726 impl Handlers {
1727 pub fn #no_method_name() -> Option<&'static Handler<#logger_type_name>> {
1729 None::<&Handler<#logger_type_name>>
1730 }
1731 }
1732
1733 #[allow(dead_code)]
1735 #(#doc_comments)*
1736 unsafe extern "C" fn #fn_name<F: #closure_type_name>(
1737 #(#args),*
1738 ) -> #closure_return_type
1739 {
1740 #[cfg(debug_assertions)]
1741 if #closure_name.is_null() {
1742 unimplemented!("closure should not be null")
1743 }
1744 #[cfg(feature = "extra-logging")]
1745 {
1746 log::debug!("calling {}", stringify!(#handle_method_name));
1747 }
1748 let closure: &mut F = &mut *(#closure_name as *mut F);
1749 closure.#handle_method_name(#(#converted_args),*)
1750 }
1751
1752 #[allow(dead_code)]
1754 #(#doc_comments)*
1755 unsafe extern "C" fn #closure_fn_name<F: FnMut(#(#fn_mut_args),*) -> #closure_return_type>(
1756 #(#args),*
1757 ) -> #closure_return_type
1758 {
1759 #[cfg(debug_assertions)]
1760 if #closure_name.is_null() {
1761 unimplemented!("closure should not be null")
1762 }
1763 #[cfg(feature = "extra-logging")]
1764 {
1765 log::debug!("calling {}", stringify!(#closure_fn_name));
1766 }
1767 let closure: &mut F = &mut *(#closure_name as *mut F);
1768 closure(#(#converted_args),*)
1769 }
1770
1771 }
1772}
1773
1774pub fn generate_rust_code(
1775 wrapper: &CWrapper,
1776 wrappers: &BTreeMap<String, CWrapper>,
1777 include_common_code: bool,
1778 include_clippy: bool,
1779 include_aeron_client_registering_resource_t: bool,
1780 closure_handlers: &Vec<CHandler>,
1781) -> TokenStream {
1782 let class_name = Ident::new(&wrapper.class_name, proc_macro2::Span::call_site());
1783 let type_name = Ident::new(&wrapper.type_name, proc_macro2::Span::call_site());
1784
1785 let mut additional_outer_impls = vec![];
1786
1787 let methods = wrapper.generate_methods(wrappers, closure_handlers, &mut additional_outer_impls);
1788 let mut constructor_fields = vec![];
1789 let mut new_ref_set_none = vec![];
1790 let constructor =
1791 wrapper.generate_constructor(wrappers, &mut constructor_fields, &mut new_ref_set_none);
1792
1793 let async_impls = if wrapper.type_name.starts_with("aeron_async_")
1794 || wrapper.type_name.starts_with("aeron_archive_async_")
1795 {
1796 let new_method = wrapper
1797 .methods
1798 .iter()
1799 .find(|m| m.fn_name == wrapper.without_name);
1800
1801 if let Some(new_method) = new_method {
1802 let main_type = &wrapper
1803 .type_name
1804 .replace("_async_", "_")
1805 .replace("_add_", "_");
1806 let main = get_possible_wrappers(main_type)
1807 .iter()
1808 .filter_map(|f| wrappers.get(f))
1809 .next()
1810 .expect(&format!("failed to find main type {}", main_type));
1811
1812 let poll_method = main
1813 .methods
1814 .iter()
1815 .find(|m| m.fn_name == format!("{}_poll", wrapper.without_name))
1816 .unwrap();
1817
1818 let main_class_name = format_ident!("{}", main.class_name);
1819 let async_class_name = format_ident!("{}", wrapper.class_name);
1820 let poll_method_name = format_ident!("{}_poll", wrapper.without_name);
1821 let new_method_name = format_ident!("{}", new_method.fn_name);
1822
1823 let client_class = wrappers
1824 .get(
1825 new_method
1826 .arguments
1827 .iter()
1828 .skip(1)
1829 .next()
1830 .unwrap()
1831 .c_type
1832 .split_whitespace()
1833 .last()
1834 .unwrap(),
1835 )
1836 .unwrap();
1837 let client_type = format_ident!("{}", client_class.class_name);
1838 let client_type_method_name = format_ident!(
1839 "{}",
1840 new_method
1841 .fn_name
1842 .replace(&format!("{}_", client_class.without_name), "")
1843 );
1844 let client_type_method_name_without_async = format_ident!(
1845 "{}",
1846 new_method
1847 .fn_name
1848 .replace(&format!("{}_", client_class.without_name), "")
1849 .replace("async_", "")
1850 );
1851
1852 let init_args: Vec<TokenStream> = poll_method
1853 .arguments
1854 .iter()
1855 .enumerate()
1856 .filter_map(|(idx, arg)| {
1857 if idx == 0 {
1858 Some(quote! { ctx_field })
1859 } else {
1860 let arg_name = arg.as_ident();
1861 let arg_name = ReturnType::new(arg.clone(), wrappers.clone())
1862 .handle_rs_to_c_return(quote! { #arg_name }, false);
1863 Some(quote! { #arg_name })
1864 }
1865 })
1866 .filter(|t| !t.is_empty())
1867 .collect();
1868
1869 let new_args: Vec<TokenStream> = poll_method
1870 .arguments
1871 .iter()
1872 .enumerate()
1873 .filter_map(|(idx, arg)| {
1874 if idx == 0 {
1875 None
1876 } else {
1877 let arg_name = arg.as_ident();
1878 let arg_type = ReturnType::new(arg.clone(), wrappers.clone())
1879 .get_new_return_type(false, true);
1880 if arg_type.clone().into_token_stream().is_empty() {
1881 None
1882 } else {
1883 Some(quote! { #arg_name: #arg_type })
1884 }
1885 }
1886 })
1887 .filter(|t| !t.is_empty())
1888 .collect();
1889
1890 let async_init_args: Vec<TokenStream> = new_method
1891 .arguments
1892 .iter()
1893 .enumerate()
1894 .filter_map(|(idx, arg)| {
1895 if idx == 0 {
1896 Some(quote! { ctx_field })
1897 } else {
1898 let arg_name = arg.as_ident();
1899 let arg_name = ReturnType::new(arg.clone(), wrappers.clone())
1900 .handle_rs_to_c_return(quote! { #arg_name }, false);
1901 Some(quote! { #arg_name })
1902 }
1903 })
1904 .filter(|t| !t.is_empty())
1905 .collect();
1906
1907 let generic_types: Vec<TokenStream> = new_method
1908 .arguments
1909 .iter()
1910 .flat_map(|arg| {
1911 ReturnType::new(arg.clone(), wrappers.clone())
1912 .method_generics_for_where()
1913 .into_iter()
1914 })
1915 .collect_vec();
1916 let where_clause_async = if generic_types.is_empty() {
1917 quote! {}
1918 } else {
1919 quote! { <#(#generic_types),*> }
1920 };
1921 let generic_types: Vec<TokenStream> = poll_method
1922 .arguments
1923 .iter()
1924 .flat_map(|arg| {
1925 ReturnType::new(arg.clone(), wrappers.clone())
1926 .method_generics_for_where()
1927 .into_iter()
1928 })
1929 .collect_vec();
1930 let where_clause_main = if generic_types.is_empty() {
1931 quote! {}
1932 } else {
1933 quote! { <#(#generic_types),*> }
1934 };
1935 let async_new_args: Vec<TokenStream> = new_method
1936 .arguments
1937 .iter()
1938 .enumerate()
1939 .filter_map(|(idx, arg)| {
1940 if idx == 0 {
1941 None
1942 } else {
1943 let arg_name = arg.as_ident();
1944 let arg_type = ReturnType::new(arg.clone(), wrappers.clone())
1945 .get_new_return_type(false, true);
1946 if arg_type.clone().into_token_stream().is_empty() {
1947 None
1948 } else {
1949 Some(quote! { #arg_name: #arg_type })
1950 }
1951 }
1952 })
1953 .filter(|t| !t.is_empty())
1954 .collect();
1955
1956 let async_dependancies = async_new_args
1957 .iter()
1958 .filter(|a| {
1959 a.to_string().contains(" : Aeron") || a.to_string().contains(" : & Aeron")
1960 })
1961 .map(|e| {
1962 let var_name =
1963 format_ident!("{}", e.to_string().split_whitespace().next().unwrap());
1964 quote! {
1965 result.inner.add_dependency(#var_name.clone());
1966 }
1967 })
1968 .collect_vec();
1969
1970 let async_new_args_for_client = async_new_args.iter().skip(1).cloned().collect_vec();
1971
1972 let async_new_args_name_only: Vec<TokenStream> = new_method
1973 .arguments
1974 .iter()
1975 .enumerate()
1976 .filter_map(|(idx, arg)| {
1977 if idx < 2 {
1978 None
1979 } else {
1980 let arg_name = arg.as_ident();
1981 let arg_type = ReturnType::new(arg.clone(), wrappers.clone())
1982 .get_new_return_type(false, false);
1983 if arg_type.clone().into_token_stream().is_empty() {
1984 None
1985 } else {
1986 Some(quote! { #arg_name })
1987 }
1988 }
1989 })
1990 .filter(|t| !t.is_empty())
1991 .collect();
1992
1993 quote! {
1994 impl #main_class_name {
1995 #[inline]
1996 pub fn new #where_clause_main (#(#new_args),*) -> Result<Self, AeronCError> {
1997 let resource = ManagedCResource::new(
1998 move |ctx_field| unsafe {
1999 #poll_method_name(#(#init_args),*)
2000 },
2001 None,
2002 false,
2003 None,
2004 )?;
2005 Ok(Self {
2006 inner: CResource::OwnedOnHeap(std::rc::Rc::new(resource)),
2007 })
2008 }
2009 }
2010
2011 impl #client_type {
2012 #[inline]
2013 pub fn #client_type_method_name #where_clause_async(&self, #(#async_new_args_for_client),*) -> Result<#async_class_name, AeronCError> {
2014 let mut result = #async_class_name::new(self, #(#async_new_args_name_only),*);
2015 if let Ok(result) = &mut result {
2016 result.inner.add_dependency(self.clone());
2017 }
2018
2019 result
2020 }
2021 }
2022
2023 impl #client_type {
2024 #[inline]
2025 pub fn #client_type_method_name_without_async #where_clause_async(&self #(
2026 , #async_new_args_for_client)*, timeout: std::time::Duration) -> Result<#main_class_name, AeronCError> {
2027 let start = std::time::Instant::now();
2028 loop {
2029 if let Ok(poller) = #async_class_name::new(self, #(#async_new_args_name_only),*) {
2030 while start.elapsed() <= timeout {
2031 if let Some(result) = poller.poll()? {
2032 return Ok(result);
2033 }
2034 #[cfg(debug_assertions)]
2035 std::thread::sleep(std::time::Duration::from_millis(10));
2036 }
2037 }
2038 if start.elapsed() > timeout {
2039 log::error!("failed async poll for {:?}", self);
2040 return Err(AeronErrorType::TimedOut.into());
2041 }
2042 #[cfg(debug_assertions)]
2043 std::thread::sleep(std::time::Duration::from_millis(10));
2044 }
2045 }
2046 }
2047
2048 impl #async_class_name {
2049 #[inline]
2050 pub fn new #where_clause_async (#(#async_new_args),*) -> Result<Self, AeronCError> {
2051 let resource_async = ManagedCResource::new(
2052 move |ctx_field| unsafe {
2053 #new_method_name(#(#async_init_args),*)
2054 },
2055 None,
2056 false,
2057 None,
2058 )?;
2059 let result = Self {
2060 inner: CResource::OwnedOnHeap(std::rc::Rc::new(resource_async)),
2061 };
2062 #(#async_dependancies)*
2063 Ok(result)
2064 }
2065
2066 pub fn poll(&self) -> Result<Option<#main_class_name>, AeronCError> {
2067
2068 let mut result = #main_class_name::new(self);
2069 if let Ok(result) = &mut result {
2070 unsafe {
2071 for d in (&mut *self.inner.as_owned().unwrap().dependencies.get()).iter_mut() {
2072 result.inner.add_dependency(d.clone());
2073 }
2074 result.inner.as_owned().unwrap().auto_close.set(true);
2075 }
2076 }
2077
2078 match result {
2079 Ok(result) => Ok(Some(result)),
2080 Err(AeronCError {code }) if code == 0 => {
2081 Ok(None) }
2083 Err(e) => Err(e)
2084 }
2085 }
2086
2087 pub fn poll_blocking(&self, timeout: std::time::Duration) -> Result<#main_class_name, AeronCError> {
2088 if let Some(result) = self.poll()? {
2089 return Ok(result);
2090 }
2091
2092 let time = std::time::Instant::now();
2093 while time.elapsed() < timeout {
2094 if let Some(result) = self.poll()? {
2095 return Ok(result);
2096 }
2097 #[cfg(debug_assertions)]
2098 std::thread::sleep(std::time::Duration::from_millis(10));
2099 }
2100 log::error!("failed async poll for {:?}", self);
2101 Err(AeronErrorType::TimedOut.into())
2102 }
2103 }
2104 }
2105 } else {
2106 quote! {}
2107 }
2108 } else {
2109 quote! {}
2110 };
2111
2112 let mut additional_impls = vec![];
2113
2114 if let Some(close_method) = wrapper.get_close_method() {
2115 if !wrapper.methods.iter().any(|m| m.fn_name.contains("_init")) {
2116 let close_method_call = if close_method.arguments.len() > 1 {
2117 let ident = format_ident!("close_with_no_args");
2118 quote! {#ident}
2119 } else {
2120 let ident = format_ident!("{}", close_method.struct_method_name);
2121 quote! {#ident}
2122 };
2123 let is_closed_method = if wrapper.get_is_closed_method().is_some() {
2124 quote! { self.is_closed() }
2125 } else {
2126 quote! { false }
2127 };
2128
2129 additional_impls.push(quote! {
2130 impl Drop for #class_name {
2131 fn drop(&mut self) {
2132 if let Some(inner) = self.inner.as_owned() {
2133 if (inner.cleanup.is_none() ) && std::rc::Rc::strong_count(inner) == 1 && !inner.is_closed_already_called() {
2134 if inner.auto_close.get() {
2135 log::info!("auto closing {}", stringify!(#class_name));
2136 let result = self.#close_method_call();
2137 log::debug!("result {:?}", result);
2138 } else {
2139 #[cfg(feature = "extra-logging")]
2140 log::warn!("{} not closed", stringify!(#class_name));
2141 }
2142 }
2143 }
2144 }
2145 }
2146 });
2147 }
2148 }
2149
2150 let common_code = if !include_common_code {
2151 quote! {}
2152 } else {
2153 TokenStream::from_str(COMMON_CODE).unwrap()
2154 };
2155 let warning_code = if !include_common_code {
2156 quote! {}
2157 } else {
2158 let mut code = String::new();
2159
2160 if include_clippy {
2161 code.push_str(
2162 " #![allow(non_upper_case_globals)]
2163 #![allow(non_camel_case_types)]
2164 #![allow(non_snake_case)]
2165 #![allow(clippy::all)]
2166 #![allow(unused_variables)]
2167 #![allow(unused_unsafe)]
2168",
2169 );
2170 }
2171
2172 if include_aeron_client_registering_resource_t {
2173 code.push_str(
2174 "
2175 type aeron_client_registering_resource_t = aeron_client_registering_resource_stct;
2176",
2177 );
2178 }
2179
2180 TokenStream::from_str(code.as_str()).unwrap()
2181 };
2182 let class_docs: Vec<TokenStream> = wrapper
2183 .docs
2184 .iter()
2185 .map(|doc| {
2186 quote! {
2187 #[doc = #doc]
2188 }
2189 })
2190 .collect();
2191
2192 let mut debug_fields = vec![];
2193 let fields = wrapper.generate_fields(&wrappers, &mut debug_fields);
2194
2195 let default_impl = if wrapper.has_default_method()
2196 && !constructor
2197 .iter()
2198 .map(|x| x.to_string())
2199 .join("")
2200 .trim()
2201 .is_empty()
2202 {
2203 quote! {
2214 impl Default for #class_name {
2216 fn default() -> Self {
2217 #class_name::new_zeroed_on_heap()
2218 }
2219 }
2220
2221 impl #class_name {
2222 pub fn clone_struct(&self) -> Self {
2231 let copy = Self::default();
2232 copy.get_inner_mut().clone_from(self.deref());
2233 copy
2234 }
2235 }
2236 }
2237 } else {
2238 quote! {}
2239 };
2240
2241 let is_closed_method = wrapper.get_is_closed_method_quote();
2242
2243 quote! {
2244 #warning_code
2245
2246 #(#class_docs)*
2247 #[derive(Clone)]
2248 pub struct #class_name {
2249 inner: CResource<#type_name>,
2250 #(#constructor_fields)*
2251 }
2252
2253 impl core::fmt::Debug for #class_name {
2254 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2255 if self.inner.get().is_null() {
2256 f.debug_struct(stringify!(#class_name))
2257 .field("inner", &"null")
2258 .finish()
2259 } else {
2260 f.debug_struct(stringify!(#class_name))
2261 .field("inner", &self.inner)
2262 #(#debug_fields)*
2263 .finish()
2264 }
2265 }
2266 }
2267
2268 impl #class_name {
2269 #(#constructor)*
2270 #(#fields)*
2271 #(#methods)*
2272
2273 #[inline(always)]
2274 pub fn get_inner(&self) -> *mut #type_name {
2275 self.inner.get()
2276 }
2277
2278 #[inline(always)]
2279 pub fn get_inner_mut(&self) -> &mut #type_name {
2280 unsafe { &mut *self.inner.get() }
2281 }
2282
2283 #[inline(always)]
2284 pub fn get_inner_ref(&self) -> & #type_name {
2285 unsafe { &*self.inner.get() }
2286 }
2287 }
2288
2289 impl std::ops::Deref for #class_name {
2290 type Target = #type_name;
2291
2292 fn deref(&self) -> &Self::Target {
2293 self.get_inner_ref()
2294 }
2295 }
2296
2297 impl From<*mut #type_name> for #class_name {
2298 #[inline]
2299 fn from(value: *mut #type_name) -> Self {
2300 #class_name {
2301 inner: CResource::Borrowed(value),
2302 #(#new_ref_set_none)*
2303 }
2304 }
2305 }
2306
2307 impl From<#class_name> for *mut #type_name {
2308 #[inline]
2309 fn from(value: #class_name) -> Self {
2310 value.get_inner()
2311 }
2312 }
2313
2314 impl From<&#class_name> for *mut #type_name {
2315 #[inline]
2316 fn from(value: &#class_name) -> Self {
2317 value.get_inner()
2318 }
2319 }
2320
2321 impl From<#class_name> for #type_name {
2322 #[inline]
2323 fn from(value: #class_name) -> Self {
2324 unsafe { *value.get_inner().clone() }
2325 }
2326 }
2327
2328 impl From<*const #type_name> for #class_name {
2329 #[inline]
2330 fn from(value: *const #type_name) -> Self {
2331 #class_name {
2332 inner: CResource::Borrowed(value as *mut #type_name),
2333 #(#new_ref_set_none)*
2334 }
2335 }
2336 }
2337
2338 impl From<#type_name> for #class_name {
2339 #[inline]
2340 fn from(mut value: #type_name) -> Self {
2341 #class_name {
2342 inner: CResource::Borrowed(&mut value as *mut #type_name),
2343 #(#new_ref_set_none)*
2344 }
2345 }
2346 }
2347
2348 #(#additional_impls)*
2349
2350 #async_impls
2351 #default_impl
2352 #common_code
2353 }
2354}