1use proc_macro::TokenStream;
135use proc_macro2::TokenStream as TokenStream2;
136use quote::{format_ident, quote};
137use std::collections::HashSet;
138use syn::parse::{Parse, ParseStream};
139use syn::{
140 FnArg, Ident, ImplItem, ImplItemFn, Item, ItemFn, ItemImpl, ItemStruct, Pat, ReturnType, Token,
141 Type, Visibility, parse_macro_input,
142};
143
144struct RingExtension {
145 prefix: Option<String>,
146 items: Vec<Item>,
147}
148
149impl Parse for RingExtension {
150 fn parse(input: ParseStream) -> syn::Result<Self> {
151 let mut prefix = None;
152 let mut items = Vec::new();
153
154 while !input.is_empty() {
155 if input.peek(Ident) {
156 let ident: Ident = input.parse()?;
157 if ident == "prefix" {
158 let _: Token![:] = input.parse()?;
159 let lit: syn::LitStr = input.parse()?;
160 let _: Token![;] = input.parse()?;
161 prefix = Some(lit.value());
162 continue;
163 } else {
164 return Err(syn::Error::new(ident.span(), "expected 'prefix' or item"));
165 }
166 }
167 items.push(input.parse()?);
168 }
169
170 Ok(RingExtension { prefix, items })
171 }
172}
173
174#[proc_macro]
176pub fn ring_extension(input: TokenStream) -> TokenStream {
177 let module = parse_macro_input!(input as RingExtension);
178
179 let prefix = module.prefix.unwrap_or_default();
180 let prefix_underscore = if prefix.is_empty() {
181 String::new()
182 } else {
183 format!("{}_", prefix)
184 };
185
186 let mut structs_with_custom_new: HashSet<String> = HashSet::new();
187 let mut impl_methods: HashSet<(String, String)> = HashSet::new();
188
189 for item in &module.items {
190 if let Item::Impl(i) = item {
191 if let Type::Path(p) = &*i.self_ty {
192 let struct_name = p.path.segments.last().unwrap().ident.to_string();
193 for impl_item in &i.items {
194 if let ImplItem::Fn(method) = impl_item {
195 let method_name = method.sig.ident.to_string();
196 if method_name == "new" {
197 structs_with_custom_new.insert(struct_name.clone());
198 }
199 impl_methods.insert((struct_name.clone(), method_name));
200 }
201 }
202 }
203 }
204 }
205
206 let mut original_items = Vec::new();
207 let mut generated_code = Vec::new();
208 let mut registrations: Vec<(String, syn::Ident)> = Vec::new();
209
210 for item in module.items {
211 match item {
212 Item::Struct(s) => {
213 let has_custom_new = structs_with_custom_new.contains(&s.ident.to_string());
214 let (orig, generated, regs) =
215 process_struct(&s, &prefix_underscore, has_custom_new, &impl_methods);
216 original_items.push(orig);
217 generated_code.push(generated);
218 registrations.extend(regs);
219 }
220 Item::Impl(i) => {
221 let (orig, generated, regs) = process_impl(&i, &prefix_underscore);
222 original_items.push(orig);
223 generated_code.push(generated);
224 registrations.extend(regs);
225 }
226 Item::Fn(f) => {
227 let (orig, generated, regs) = process_function(&f, &prefix_underscore);
228 original_items.push(orig);
229 generated_code.push(generated);
230 registrations.extend(regs);
231 }
232 other => {
233 original_items.push(quote! { #other });
234 }
235 }
236 }
237
238 let libinit_entries: Vec<_> = registrations
239 .iter()
240 .map(|(name, fn_ident)| {
241 quote! { #name => #fn_ident }
242 })
243 .collect();
244
245 let expanded = quote! {
246 #(#original_items)*
247 #(#generated_code)*
248
249 ring_libinit! {
250 #(#libinit_entries),*
251 }
252 };
253
254 expanded.into()
255}
256
257fn process_struct(
258 s: &ItemStruct,
259 prefix: &str,
260 has_custom_new: bool,
261 impl_methods: &HashSet<(String, String)>,
262) -> (TokenStream2, TokenStream2, Vec<(String, syn::Ident)>) {
263 let struct_name = &s.ident;
264 let struct_name_lower = struct_name.to_string().to_lowercase();
265 let type_const = format_ident!("{}_TYPE", struct_name.to_string().to_uppercase());
266 let type_const_str = format!("{}\0", struct_name);
267
268 let mut regs = Vec::new();
269
270 let delete_fn_name = format_ident!("ring_{}{}_delete", prefix, struct_name_lower);
271 let delete_ring_name = format!("{}{}_delete", prefix, struct_name_lower);
272 regs.push((delete_ring_name, delete_fn_name.clone()));
273
274 let new_code = if !has_custom_new {
275 let new_fn_name = format_ident!("ring_{}{}_new", prefix, struct_name_lower);
276 let new_ring_name = format!("{}{}_new", prefix, struct_name_lower);
277 regs.push((new_ring_name, new_fn_name.clone()));
278
279 quote! {
280 ring_func!(#new_fn_name, |p| {
281 ring_check_paracount!(p, 0);
282 let obj = Box::new(#struct_name::default());
283 ring_ret_cpointer!(p, Box::into_raw(obj), #type_const);
284 });
285 }
286 } else {
287 quote! {}
288 };
289
290 let mut accessors = Vec::new();
291 let struct_name_str = struct_name.to_string();
292
293 if let syn::Fields::Named(fields) = &s.fields {
294 for field in &fields.named {
295 if !matches!(field.vis, Visibility::Public(_)) {
296 continue;
297 }
298
299 let field_name = field.ident.as_ref().unwrap();
300 let field_name_str = field_name.to_string();
301 let field_type = &field.ty;
302
303 let getter_method = format!("get_{}", field_name_str);
304 let setter_method = format!("set_{}", field_name_str);
305
306 if !impl_methods.contains(&(struct_name_str.clone(), getter_method.clone()))
307 && !impl_methods.contains(&(struct_name_str.clone(), field_name_str.clone()))
308 {
309 let getter_fn =
310 format_ident!("ring_{}{}_get_{}", prefix, struct_name_lower, field_name);
311 let getter_name = format!("{}{}_get_{}", prefix, struct_name_lower, field_name);
312 regs.push((getter_name, getter_fn.clone()));
313
314 let getter_code = generate_field_getter(
315 &getter_fn,
316 struct_name,
317 &type_const,
318 field_name,
319 field_type,
320 );
321 accessors.push(getter_code);
322 }
323
324 if !impl_methods.contains(&(struct_name_str.clone(), setter_method)) {
325 let setter_fn =
326 format_ident!("ring_{}{}_set_{}", prefix, struct_name_lower, field_name);
327 let setter_name = format!("{}{}_set_{}", prefix, struct_name_lower, field_name);
328 regs.push((setter_name, setter_fn.clone()));
329
330 let setter_code = generate_field_setter(
331 &setter_fn,
332 struct_name,
333 &type_const,
334 field_name,
335 field_type,
336 );
337 accessors.push(setter_code);
338 }
339 }
340 }
341
342 let original = quote! { #s };
343
344 let generated = quote! {
345 const #type_const: &[u8] = #type_const_str.as_bytes();
346
347 #new_code
348
349 ring_func!(#delete_fn_name, |p| {
350 ring_check_paracount!(p, 1);
351 ring_check_cpointer!(p, 1);
352 let ptr = ring_get_cpointer!(p, 1, #type_const);
353 if !ptr.is_null() {
354 unsafe { let _ = Box::from_raw(ptr as *mut #struct_name); }
355 }
356 });
357
358 #(#accessors)*
359 };
360
361 (original, generated, regs)
362}
363
364fn process_impl(
365 i: &ItemImpl,
366 prefix: &str,
367) -> (TokenStream2, TokenStream2, Vec<(String, syn::Ident)>) {
368 let struct_name = match &*i.self_ty {
369 Type::Path(p) => p.path.segments.last().unwrap().ident.clone(),
370 _ => return (quote! { #i }, quote! {}, vec![]),
371 };
372
373 let struct_name_lower = struct_name.to_string().to_lowercase();
374 let type_const = format_ident!("{}_TYPE", struct_name.to_string().to_uppercase());
375
376 let mut regs = Vec::new();
377 let mut method_wrappers = Vec::new();
378
379 for item in &i.items {
380 if let ImplItem::Fn(method) = item {
381 if !matches!(method.vis, Visibility::Public(_)) {
382 continue;
383 }
384
385 let method_name = &method.sig.ident;
386 let method_name_str = method_name.to_string();
387
388 if method_name_str == "new" {
389 let (code, name, fn_ident) = generate_custom_new(
390 &struct_name,
391 &struct_name_lower,
392 &type_const,
393 method,
394 prefix,
395 );
396 method_wrappers.push(code);
397 regs.push((name, fn_ident));
398 continue;
399 }
400
401 let has_self = method
402 .sig
403 .inputs
404 .iter()
405 .any(|arg| matches!(arg, FnArg::Receiver(_)));
406
407 if has_self {
408 let (code, name, fn_ident) = generate_method(
409 &struct_name,
410 &struct_name_lower,
411 &type_const,
412 method,
413 prefix,
414 );
415 method_wrappers.push(code);
416 regs.push((name, fn_ident));
417 } else {
418 let (code, name, fn_ident) = generate_static_method(
419 &struct_name,
420 &struct_name_lower,
421 &type_const,
422 method,
423 prefix,
424 );
425 method_wrappers.push(code);
426 regs.push((name, fn_ident));
427 }
428 }
429 }
430
431 let original = quote! { #i };
432 let generated = quote! { #(#method_wrappers)* };
433
434 (original, generated, regs)
435}
436
437fn process_function(
438 f: &ItemFn,
439 prefix: &str,
440) -> (TokenStream2, TokenStream2, Vec<(String, syn::Ident)>) {
441 let fn_name = &f.sig.ident;
442 let ring_fn_name = format_ident!("ring_{}{}", prefix, fn_name);
443 let ring_name = format!("{}{}", prefix, fn_name);
444
445 let params: Vec<_> = f
446 .sig
447 .inputs
448 .iter()
449 .filter_map(|arg| {
450 if let FnArg::Typed(pat) = arg {
451 let name = if let Pat::Ident(ident) = &*pat.pat {
452 ident.ident.clone()
453 } else {
454 return None;
455 };
456 Some((name, (*pat.ty).clone()))
457 } else {
458 None
459 }
460 })
461 .collect();
462
463 let param_count = params.len();
464 let mut checks = Vec::new();
465 let mut gets = Vec::new();
466 let mut args = Vec::new();
467
468 for (i, (name, ty)) in params.iter().enumerate() {
469 let idx = (i + 1) as i32;
470 let binding = generate_param_binding(name, ty, idx);
471 checks.push(binding.check);
472 gets.push(binding.get);
473 args.push(binding.arg);
474 }
475
476 let param_count_i32 = param_count as i32;
477 let return_code = generate_return_code(&f.sig.output, quote! { #fn_name(#(#args),*) });
478
479 let original = quote! { #f };
480 let generated = quote! {
481 ring_func!(#ring_fn_name, |p| {
482 ring_check_paracount!(p, #param_count_i32);
483 #(#checks)*
484 #(#gets)*
485 #return_code
486 });
487 };
488
489 (original, generated, vec![(ring_name, ring_fn_name)])
490}
491
492fn generate_field_getter(
493 fn_name: &syn::Ident,
494 struct_name: &syn::Ident,
495 type_const: &syn::Ident,
496 field_name: &syn::Ident,
497 field_type: &Type,
498) -> TokenStream2 {
499 let type_str = quote!(#field_type).to_string();
500 let return_expr = if is_number_type(&type_str) {
501 quote! { ring_ret_number!(p, obj.#field_name as f64); }
502 } else if is_string_type(&type_str) {
503 quote! { ring_ret_string!(p, &obj.#field_name); }
504 } else if type_str == "bool" {
505 quote! { ring_ret_number!(p, if obj.#field_name { 1.0 } else { 0.0 }); }
506 } else if is_vec_type(&type_str) {
507 let inner = extract_vec_inner(&type_str).unwrap_or_default();
508 if is_number_type(&inner) {
509 quote! {
510 let __list = ring_new_list!(p);
511 for __item in &obj.#field_name {
512 ring_list_adddouble(__list, *__item as f64);
513 }
514 ring_ret_list!(p, __list);
515 }
516 } else if is_string_type(&inner) {
517 quote! {
518 let __list = ring_new_list!(p);
519 for __item in &obj.#field_name {
520 ring_list_addstring_str(__list, &__item);
521 }
522 ring_ret_list!(p, __list);
523 }
524 } else if is_struct_type(&inner) {
525 let inner_type_const = struct_type_const(&extract_struct_name(&inner));
526 quote! {
527 let __list = ring_new_list!(p);
528 for __item in &obj.#field_name {
529 let __ptr = Box::into_raw(Box::new(__item.clone()));
530 ring_list_addcpointer(__list, __ptr as *mut std::ffi::c_void, #inner_type_const);
531 }
532 ring_ret_list!(p, __list);
533 }
534 } else {
535 quote! {
536 let __list = ring_new_list!(p);
537 for __item in &obj.#field_name {
538 ring_list_adddouble(__list, *__item as f64);
539 }
540 ring_ret_list!(p, __list);
541 }
542 }
543 } else if is_option_type(&type_str) {
544 let inner = extract_option_inner(&type_str).unwrap_or_default();
545 if is_number_type(&inner) {
546 quote! {
547 match &obj.#field_name {
548 Some(__val) => ring_ret_number!(p, *__val as f64),
549 None => {},
550 }
551 }
552 } else if is_string_type(&inner) {
553 quote! {
554 match &obj.#field_name {
555 Some(__val) => ring_ret_string!(p, __val),
556 None => {},
557 }
558 }
559 } else if is_struct_type(&inner) {
560 let inner_type_const = struct_type_const(&extract_struct_name(&inner));
561 quote! {
562 match &obj.#field_name {
563 Some(__val) => {
564 ring_ret_cpointer!(p, Box::into_raw(Box::new(__val.clone())), #inner_type_const);
565 }
566 None => {},
567 }
568 }
569 } else {
570 quote! {
571 match &obj.#field_name {
572 Some(__val) => ring_ret_number!(p, *__val as f64),
573 None => {},
574 }
575 }
576 }
577 } else if is_struct_type(&type_str) {
578 let field_type_const = struct_type_const(&extract_struct_name(&type_str));
579 quote! {
580 ring_ret_cpointer!(p, Box::into_raw(Box::new(obj.#field_name.clone())), #field_type_const);
581 }
582 } else {
583 quote! { ring_ret_number!(p, obj.#field_name as f64); }
584 };
585
586 quote! {
587 ring_func!(#fn_name, |p| {
588 ring_check_paracount!(p, 1);
589 ring_check_cpointer!(p, 1);
590 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
591 #return_expr
592 } else {
593 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
594 }
595 });
596 }
597}
598
599fn generate_field_setter(
600 fn_name: &syn::Ident,
601 struct_name: &syn::Ident,
602 type_const: &syn::Ident,
603 field_name: &syn::Ident,
604 field_type: &Type,
605) -> TokenStream2 {
606 let type_str = quote!(#field_type).to_string();
607
608 if is_number_type(&type_str) {
609 let cast = get_number_cast(&type_str);
610 quote! {
611 ring_func!(#fn_name, |p| {
612 ring_check_paracount!(p, 2);
613 ring_check_cpointer!(p, 1);
614 ring_check_number!(p, 2);
615 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
616 obj.#field_name = ring_get_number!(p, 2) as #cast;
617 } else {
618 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
619 }
620 });
621 }
622 } else if is_string_type(&type_str) {
623 quote! {
624 ring_func!(#fn_name, |p| {
625 ring_check_paracount!(p, 2);
626 ring_check_cpointer!(p, 1);
627 ring_check_string!(p, 2);
628 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
629 obj.#field_name = ring_get_string!(p, 2).to_string();
630 } else {
631 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
632 }
633 });
634 }
635 } else if type_str == "bool" {
636 quote! {
637 ring_func!(#fn_name, |p| {
638 ring_check_paracount!(p, 2);
639 ring_check_cpointer!(p, 1);
640 ring_check_number!(p, 2);
641 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
642 obj.#field_name = ring_get_number!(p, 2) != 0.0;
643 } else {
644 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
645 }
646 });
647 }
648 } else if is_vec_type(&type_str) {
649 let inner = extract_vec_inner(&type_str).unwrap_or_default();
650 if is_number_type(&inner) {
651 let cast = get_number_cast(&inner);
652 quote! {
653 ring_func!(#fn_name, |p| {
654 ring_check_paracount!(p, 2);
655 ring_check_cpointer!(p, 1);
656 ring_check_list!(p, 2);
657 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
658 let __list = ring_get_list!(p, 2);
659 let __size = ring_list_getsize(__list);
660 let mut __vec = Vec::with_capacity(__size as usize);
661 for __i in 1..=__size {
662 if ring_list_isnumber(__list, __i) {
663 __vec.push(ring_list_getdouble(__list, __i) as #cast);
664 }
665 }
666 obj.#field_name = __vec;
667 } else {
668 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
669 }
670 });
671 }
672 } else if is_string_type(&inner) {
673 quote! {
674 ring_func!(#fn_name, |p| {
675 ring_check_paracount!(p, 2);
676 ring_check_cpointer!(p, 1);
677 ring_check_list!(p, 2);
678 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
679 let __list = ring_get_list!(p, 2);
680 let __size = ring_list_getsize(__list);
681 let mut __vec = Vec::with_capacity(__size as usize);
682 for __i in 1..=__size {
683 if ring_list_isstring(__list, __i) {
684 let __cstr = ring_list_getstring(__list, __i);
685 let __s = unsafe { std::ffi::CStr::from_ptr(__cstr).to_string_lossy().into_owned() };
686 __vec.push(__s);
687 }
688 }
689 obj.#field_name = __vec;
690 } else {
691 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
692 }
693 });
694 }
695 } else if is_struct_type(&inner) {
696 let inner_struct_name = extract_struct_name(&inner);
697 let inner_struct_ident = format_ident!("{}", inner_struct_name);
698 quote! {
699 ring_func!(#fn_name, |p| {
700 ring_check_paracount!(p, 2);
701 ring_check_cpointer!(p, 1);
702 ring_check_list!(p, 2);
703 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
704 let __list = ring_get_list!(p, 2);
705 let __size = ring_list_getsize(__list);
706 let mut __vec = Vec::with_capacity(__size as usize);
707 for __i in 1..=__size {
708 let __ptr = if ring_list_ispointer(__list, __i) {
709 ring_list_getpointer(__list, __i)
710 } else if ring_list_islist(__list, __i) {
711 let __inner_list = ring_list_getlist(__list, __i);
712 if ring_list_ispointer(__inner_list, 1) {
713 ring_list_getpointer(__inner_list, 1)
714 } else {
715 std::ptr::null_mut()
716 }
717 } else {
718 std::ptr::null_mut()
719 };
720 if !__ptr.is_null() {
721 let __item = unsafe { &*(__ptr as *const #inner_struct_ident) };
722 __vec.push(__item.clone());
723 }
724 }
725 obj.#field_name = __vec;
726 } else {
727 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
728 }
729 });
730 }
731 } else {
732 let cast = get_number_cast(&inner);
733 quote! {
734 ring_func!(#fn_name, |p| {
735 ring_check_paracount!(p, 2);
736 ring_check_cpointer!(p, 1);
737 ring_check_list!(p, 2);
738 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
739 let __list = ring_get_list!(p, 2);
740 let __size = ring_list_getsize(__list);
741 let mut __vec = Vec::with_capacity(__size as usize);
742 for __i in 1..=__size {
743 if ring_list_isnumber(__list, __i) {
744 __vec.push(ring_list_getdouble(__list, __i) as #cast);
745 }
746 }
747 obj.#field_name = __vec;
748 } else {
749 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
750 }
751 });
752 }
753 }
754 } else if is_option_type(&type_str) {
755 let inner = extract_option_inner(&type_str).unwrap_or_default();
756 if is_number_type(&inner) {
757 let cast = get_number_cast(&inner);
758 quote! {
759 ring_func!(#fn_name, |p| {
760 ring_check_paracount!(p, 2);
761 ring_check_cpointer!(p, 1);
762 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
763 if ring_api_isstring(p, 2) {
764 let __s = ring_get_string!(p, 2);
765 if __s.is_empty() {
766 obj.#field_name = None;
767 } else {
768 ring_error!(p, "Expected number or empty string for Option");
769 }
770 } else if ring_api_isnumber(p, 2) {
771 obj.#field_name = Some(ring_get_number!(p, 2) as #cast);
772 } else {
773 ring_error!(p, "Expected number or empty string for Option");
774 }
775 } else {
776 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
777 }
778 });
779 }
780 } else if is_string_type(&inner) {
781 quote! {
782 ring_func!(#fn_name, |p| {
783 ring_check_paracount!(p, 2);
784 ring_check_cpointer!(p, 1);
785 ring_check_string!(p, 2);
786 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
787 let __s = ring_get_string!(p, 2);
788 if __s.is_empty() {
789 obj.#field_name = None;
790 } else {
791 obj.#field_name = Some(__s.to_string());
792 }
793 } else {
794 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
795 }
796 });
797 }
798 } else if is_struct_type(&inner) {
799 let inner_struct_name = extract_struct_name(&inner);
800 let inner_struct_ident = format_ident!("{}", inner_struct_name);
801 let inner_type_const = struct_type_const(&inner_struct_name);
802 quote! {
803 ring_func!(#fn_name, |p| {
804 ring_check_paracount!(p, 2);
805 ring_check_cpointer!(p, 1);
806 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
807 if ring_api_isstring(p, 2) {
808 let __s = ring_get_string!(p, 2);
809 if __s.is_empty() {
810 obj.#field_name = None;
811 } else {
812 ring_error!(p, "Expected cpointer or empty string for Option<Struct>");
813 }
814 } else if ring_api_ispointer(p, 2) {
815 let __ptr = ring_get_cpointer!(p, 2, #inner_type_const);
816 if __ptr.is_null() {
817 obj.#field_name = None;
818 } else {
819 let __val = unsafe { &*(__ptr as *const #inner_struct_ident) };
820 obj.#field_name = Some(__val.clone());
821 }
822 } else {
823 ring_error!(p, "Expected cpointer or empty string for Option<Struct>");
824 }
825 } else {
826 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
827 }
828 });
829 }
830 } else {
831 let cast = get_number_cast(&inner);
832 quote! {
833 ring_func!(#fn_name, |p| {
834 ring_check_paracount!(p, 2);
835 ring_check_cpointer!(p, 1);
836 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
837 if ring_api_isstring(p, 2) {
838 let __s = ring_get_string!(p, 2);
839 if __s.is_empty() {
840 obj.#field_name = None;
841 } else {
842 ring_error!(p, "Expected number or empty string for Option");
843 }
844 } else if ring_api_isnumber(p, 2) {
845 obj.#field_name = Some(ring_get_number!(p, 2) as #cast);
846 } else {
847 ring_error!(p, "Expected number or empty string for Option");
848 }
849 } else {
850 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
851 }
852 });
853 }
854 }
855 } else if is_struct_type(&type_str) {
856 let field_struct_name = extract_struct_name(&type_str);
857 let field_struct_ident = format_ident!("{}", field_struct_name);
858 let field_type_const = struct_type_const(&field_struct_name);
859 quote! {
860 ring_func!(#fn_name, |p| {
861 ring_check_paracount!(p, 2);
862 ring_check_cpointer!(p, 1);
863 ring_check_cpointer!(p, 2);
864 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
865 if let Some(val) = ring_get_pointer!(p, 2, #field_struct_ident, #field_type_const) {
866 obj.#field_name = val.clone();
867 } else {
868 ring_error!(p, concat!("Invalid ", #field_struct_name, " pointer"));
869 }
870 } else {
871 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
872 }
873 });
874 }
875 } else {
876 quote! {
877 ring_func!(#fn_name, |p| {
878 ring_check_paracount!(p, 2);
879 ring_check_cpointer!(p, 1);
880 ring_check_number!(p, 2);
881 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
882 obj.#field_name = ring_get_number!(p, 2) as _;
883 } else {
884 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
885 }
886 });
887 }
888 }
889}
890
891fn generate_custom_new(
892 struct_name: &syn::Ident,
893 struct_name_lower: &str,
894 type_const: &syn::Ident,
895 method: &ImplItemFn,
896 prefix: &str,
897) -> (TokenStream2, String, syn::Ident) {
898 let fn_name = format_ident!("ring_{}{}_new", prefix, struct_name_lower);
899 let ring_name = format!("{}{}_new", prefix, struct_name_lower);
900
901 let params: Vec<_> = method
902 .sig
903 .inputs
904 .iter()
905 .filter_map(|arg| {
906 if let FnArg::Typed(pat) = arg {
907 let name = if let Pat::Ident(ident) = &*pat.pat {
908 ident.ident.clone()
909 } else {
910 return None;
911 };
912 Some((name, (*pat.ty).clone()))
913 } else {
914 None
915 }
916 })
917 .collect();
918
919 let param_count = params.len() as i32;
920 let mut checks = Vec::new();
921 let mut gets = Vec::new();
922 let mut args = Vec::new();
923
924 for (i, (name, ty)) in params.iter().enumerate() {
925 let idx = (i + 1) as i32;
926 let binding = generate_param_binding(name, ty, idx);
927 checks.push(binding.check);
928 gets.push(binding.get);
929 args.push(binding.arg);
930 }
931
932 let code = quote! {
933 ring_func!(#fn_name, |p| {
934 ring_check_paracount!(p, #param_count);
935 #(#checks)*
936 #(#gets)*
937 let obj = Box::new(#struct_name::new(#(#args),*));
938 ring_ret_cpointer!(p, Box::into_raw(obj), #type_const);
939 });
940 };
941
942 (code, ring_name, fn_name)
943}
944
945fn generate_method(
946 struct_name: &syn::Ident,
947 struct_name_lower: &str,
948 type_const: &syn::Ident,
949 method: &ImplItemFn,
950 prefix: &str,
951) -> (TokenStream2, String, syn::Ident) {
952 let method_name = &method.sig.ident;
953 let fn_name = format_ident!("ring_{}{}_{}", prefix, struct_name_lower, method_name);
954 let ring_name = format!("{}{}_{}", prefix, struct_name_lower, method_name);
955
956 let params: Vec<_> = method
957 .sig
958 .inputs
959 .iter()
960 .filter_map(|arg| {
961 if let FnArg::Typed(pat) = arg {
962 let name = if let Pat::Ident(ident) = &*pat.pat {
963 ident.ident.clone()
964 } else {
965 return None;
966 };
967 Some((name, (*pat.ty).clone()))
968 } else {
969 None
970 }
971 })
972 .collect();
973
974 let param_count = (params.len() + 1) as i32;
975 let mut checks = Vec::new();
976 let mut gets = Vec::new();
977 let mut args = Vec::new();
978
979 for (i, (name, ty)) in params.iter().enumerate() {
980 let idx = (i + 2) as i32;
981 let binding = generate_param_binding(name, ty, idx);
982 checks.push(binding.check);
983 gets.push(binding.get);
984 args.push(binding.arg);
985 }
986
987 let return_code = generate_return_code_with_context(
988 &method.sig.output,
989 quote! { obj.#method_name(#(#args),*) },
990 Some(struct_name),
991 );
992
993 let code = quote! {
994 ring_func!(#fn_name, |p| {
995 ring_check_paracount!(p, #param_count);
996 ring_check_cpointer!(p, 1);
997 #(#checks)*
998 if let Some(obj) = ring_get_pointer!(p, 1, #struct_name, #type_const) {
999 #(#gets)*
1000 #return_code
1001 } else {
1002 ring_error!(p, concat!("Invalid ", stringify!(#struct_name), " pointer"));
1003 }
1004 });
1005 };
1006
1007 (code, ring_name, fn_name)
1008}
1009
1010fn generate_static_method(
1011 struct_name: &syn::Ident,
1012 struct_name_lower: &str,
1013 _type_const: &syn::Ident,
1014 method: &ImplItemFn,
1015 prefix: &str,
1016) -> (TokenStream2, String, syn::Ident) {
1017 let method_name = &method.sig.ident;
1018 let fn_name = format_ident!("ring_{}{}_{}", prefix, struct_name_lower, method_name);
1019 let ring_name = format!("{}{}_{}", prefix, struct_name_lower, method_name);
1020
1021 let params: Vec<_> = method
1022 .sig
1023 .inputs
1024 .iter()
1025 .filter_map(|arg| {
1026 if let FnArg::Typed(pat) = arg {
1027 let name = if let Pat::Ident(ident) = &*pat.pat {
1028 ident.ident.clone()
1029 } else {
1030 return None;
1031 };
1032 Some((name, (*pat.ty).clone()))
1033 } else {
1034 None
1035 }
1036 })
1037 .collect();
1038
1039 let param_count = params.len() as i32;
1040 let mut checks = Vec::new();
1041 let mut gets = Vec::new();
1042 let mut args = Vec::new();
1043
1044 for (i, (name, ty)) in params.iter().enumerate() {
1045 let idx = (i + 1) as i32;
1046 let binding = generate_param_binding(name, ty, idx);
1047 checks.push(binding.check);
1048 gets.push(binding.get);
1049 args.push(binding.arg);
1050 }
1051
1052 let return_code = generate_return_code_with_context(
1053 &method.sig.output,
1054 quote! { #struct_name::#method_name(#(#args),*) },
1055 Some(struct_name),
1056 );
1057
1058 let code = quote! {
1059 ring_func!(#fn_name, |p| {
1060 ring_check_paracount!(p, #param_count);
1061 #(#checks)*
1062 #(#gets)*
1063 #return_code
1064 });
1065 };
1066
1067 (code, ring_name, fn_name)
1068}
1069
1070fn generate_return_code(output: &ReturnType, call: TokenStream2) -> TokenStream2 {
1071 generate_return_code_with_context(output, call, None)
1072}
1073
1074fn generate_return_code_with_context(
1075 output: &ReturnType,
1076 call: TokenStream2,
1077 self_struct: Option<&syn::Ident>,
1078) -> TokenStream2 {
1079 match output {
1080 ReturnType::Default => quote! { #call; },
1081 ReturnType::Type(_, ty) => {
1082 let type_str = quote!(#ty).to_string();
1083 generate_return_for_type(&type_str, call, self_struct)
1084 }
1085 }
1086}
1087
1088fn generate_return_for_type(
1089 type_str: &str,
1090 call: TokenStream2,
1091 self_struct: Option<&syn::Ident>,
1092) -> TokenStream2 {
1093 let type_str = type_str.trim();
1094
1095 if is_number_type(type_str) {
1096 quote! {
1097 let __result = #call;
1098 ring_ret_number!(p, __result as f64);
1099 }
1100 } else if is_string_type(type_str) {
1101 quote! {
1102 let __result = #call;
1103 ring_ret_string!(p, &__result);
1104 }
1105 } else if type_str == "bool" {
1106 quote! {
1107 let __result = #call;
1108 ring_ret_number!(p, if __result { 1.0 } else { 0.0 });
1109 }
1110 } else if is_vec_type(type_str) {
1111 generate_vec_return(type_str, call)
1112 } else if is_option_type(type_str) {
1113 generate_option_return(type_str, call)
1114 } else if is_result_type(type_str) {
1115 generate_result_return(type_str, call)
1116 } else if is_tuple_type(type_str) {
1117 generate_tuple_return(type_str, call)
1118 } else if is_box_type(type_str) {
1119 generate_box_return(type_str, call)
1120 } else if is_hashmap_type(type_str) {
1121 generate_hashmap_return(type_str, call)
1122 } else if type_str == "Self" {
1123 if let Some(struct_name) = self_struct {
1124 let type_const = struct_type_const(&struct_name.to_string());
1125 quote! {
1126 let __result = #call;
1127 ring_ret_cpointer!(p, Box::into_raw(Box::new(__result)), #type_const);
1128 }
1129 } else {
1130 quote! {
1131 let __result = #call;
1132 ring_ret_number!(p, __result as f64);
1133 }
1134 }
1135 } else if is_struct_type(type_str) {
1136 let struct_name = extract_struct_name(type_str);
1137 let type_const = struct_type_const(&struct_name);
1138 quote! {
1139 let __result = #call;
1140 ring_ret_cpointer!(p, Box::into_raw(Box::new(__result)), #type_const);
1141 }
1142 } else {
1143 quote! {
1144 let __result = #call;
1145 ring_ret_number!(p, __result as f64);
1146 }
1147 }
1148}
1149
1150fn generate_vec_return(type_str: &str, call: TokenStream2) -> TokenStream2 {
1151 let inner = extract_vec_inner(type_str).unwrap_or_default();
1152
1153 if is_number_type(&inner) {
1154 quote! {
1155 let __result = #call;
1156 let __list = ring_new_list!(p);
1157 for __item in __result {
1158 ring_list_adddouble(__list, __item as f64);
1159 }
1160 ring_ret_list!(p, __list);
1161 }
1162 } else if is_string_type(&inner) {
1163 quote! {
1164 let __result = #call;
1165 let __list = ring_new_list!(p);
1166 for __item in __result {
1167 ring_list_addstring_str(__list, &__item);
1168 }
1169 ring_ret_list!(p, __list);
1170 }
1171 } else if is_option_type(&inner) {
1172 let opt_inner = extract_option_inner(&inner).unwrap_or_default();
1173 if is_number_type(&opt_inner) {
1174 quote! {
1175 let __result = #call;
1176 let __list = ring_new_list!(p);
1177 for __item in __result {
1178 match __item {
1179 Some(__val) => ring_list_adddouble(__list, __val as f64),
1180 None => ring_list_newitem(__list),
1181 }
1182 }
1183 ring_ret_list!(p, __list);
1184 }
1185 } else if is_string_type(&opt_inner) {
1186 quote! {
1187 let __result = #call;
1188 let __list = ring_new_list!(p);
1189 for __item in __result {
1190 match __item {
1191 Some(__val) => ring_list_addstring_str(__list, &__val),
1192 None => ring_list_newitem(__list),
1193 }
1194 }
1195 ring_ret_list!(p, __list);
1196 }
1197 } else if is_struct_type(&opt_inner) {
1198 let type_const = struct_type_const(&extract_struct_name(&opt_inner));
1199 quote! {
1200 let __result = #call;
1201 let __list = ring_new_list!(p);
1202 for __item in __result {
1203 match __item {
1204 Some(__val) => {
1205 let __ptr = Box::into_raw(Box::new(__val));
1206 ring_list_addcpointer(__list, __ptr as *mut std::ffi::c_void, #type_const);
1207 }
1208 None => ring_list_newitem(__list),
1209 }
1210 }
1211 ring_ret_list!(p, __list);
1212 }
1213 } else {
1214 quote! {
1215 let __result = #call;
1216 let __list = ring_new_list!(p);
1217 for __item in __result {
1218 match __item {
1219 Some(__val) => ring_list_adddouble(__list, __val as f64),
1220 None => ring_list_newitem(__list),
1221 }
1222 }
1223 ring_ret_list!(p, __list);
1224 }
1225 }
1226 } else if is_vec_type(&inner) {
1227 let inner_inner = extract_vec_inner(&inner).unwrap_or_default();
1228 let add_inner_item = if is_number_type(&inner_inner) {
1229 quote! { ring_list_adddouble(__inner_list, __inner_item as f64); }
1230 } else if is_string_type(&inner_inner) {
1231 quote! { ring_list_addstring_str(__inner_list, &__inner_item); }
1232 } else if is_struct_type(&inner_inner) {
1233 let type_const = struct_type_const(&extract_struct_name(&inner_inner));
1234 quote! {
1235 let __ptr = Box::into_raw(Box::new(__inner_item));
1236 ring_list_addcpointer(__inner_list, __ptr as *mut std::ffi::c_void, #type_const);
1237 }
1238 } else {
1239 quote! { ring_list_adddouble(__inner_list, __inner_item as f64); }
1240 };
1241
1242 quote! {
1243 let __result = #call;
1244 let __list = ring_new_list!(p);
1245 for __item in __result {
1246 let __inner_list = ring_list_newlist(__list);
1247 for __inner_item in __item {
1248 #add_inner_item
1249 }
1250 }
1251 ring_ret_list!(p, __list);
1252 }
1253 } else if is_struct_type(&inner) {
1254 let type_const = struct_type_const(&extract_struct_name(&inner));
1255 quote! {
1256 let __result = #call;
1257 let __list = ring_new_list!(p);
1258 for __item in __result {
1259 let __ptr = Box::into_raw(Box::new(__item));
1260 ring_list_addcpointer(__list, __ptr as *mut std::ffi::c_void, #type_const);
1261 }
1262 ring_ret_list!(p, __list);
1263 }
1264 } else {
1265 quote! {
1266 let __result = #call;
1267 let __list = ring_new_list!(p);
1268 for __item in __result {
1269 ring_list_adddouble(__list, __item as f64);
1270 }
1271 ring_ret_list!(p, __list);
1272 }
1273 }
1274}
1275
1276fn generate_option_return(type_str: &str, call: TokenStream2) -> TokenStream2 {
1277 let inner = extract_option_inner(type_str).unwrap_or_default();
1278
1279 if is_number_type(&inner) {
1280 quote! {
1281 let __result = #call;
1282 match __result {
1283 Some(__val) => ring_ret_number!(p, __val as f64),
1284 None => {},
1285 }
1286 }
1287 } else if is_string_type(&inner) {
1288 quote! {
1289 let __result = #call;
1290 match __result {
1291 Some(__val) => ring_ret_string!(p, &__val),
1292 None => {},
1293 }
1294 }
1295 } else if is_vec_type(&inner) {
1296 let vec_inner = extract_vec_inner(&inner).unwrap_or_default();
1297 if is_number_type(&vec_inner) {
1298 quote! {
1299 let __result = #call;
1300 match __result {
1301 Some(__vec) => {
1302 let __list = ring_new_list!(p);
1303 for __item in __vec {
1304 ring_list_adddouble(__list, __item as f64);
1305 }
1306 ring_ret_list!(p, __list);
1307 }
1308 None => {},
1309 }
1310 }
1311 } else if is_string_type(&vec_inner) {
1312 quote! {
1313 let __result = #call;
1314 match __result {
1315 Some(__vec) => {
1316 let __list = ring_new_list!(p);
1317 for __item in __vec {
1318 ring_list_addstring_str(__list, &__item);
1319 }
1320 ring_ret_list!(p, __list);
1321 }
1322 None => {},
1323 }
1324 }
1325 } else if is_struct_type(&vec_inner) {
1326 let type_const = struct_type_const(&extract_struct_name(&vec_inner));
1327 quote! {
1328 let __result = #call;
1329 match __result {
1330 Some(__vec) => {
1331 let __list = ring_new_list!(p);
1332 for __item in __vec {
1333 let __ptr = Box::into_raw(Box::new(__item));
1334 ring_list_addcpointer(__list, __ptr as *mut std::ffi::c_void, #type_const);
1335 }
1336 ring_ret_list!(p, __list);
1337 }
1338 None => {},
1339 }
1340 }
1341 } else {
1342 quote! {
1343 let __result = #call;
1344 match __result {
1345 Some(__vec) => {
1346 let __list = ring_new_list!(p);
1347 for __item in __vec {
1348 ring_list_adddouble(__list, __item as f64);
1349 }
1350 ring_ret_list!(p, __list);
1351 }
1352 None => {},
1353 }
1354 }
1355 }
1356 } else if is_struct_type(&inner) {
1357 let type_const = struct_type_const(&extract_struct_name(&inner));
1358 quote! {
1359 let __result = #call;
1360 match __result {
1361 Some(__val) => {
1362 ring_ret_cpointer!(p, Box::into_raw(Box::new(__val)), #type_const);
1363 }
1364 None => {},
1365 }
1366 }
1367 } else {
1368 quote! {
1369 let __result = #call;
1370 match __result {
1371 Some(__val) => ring_ret_number!(p, __val as f64),
1372 None => {},
1373 }
1374 }
1375 }
1376}
1377
1378fn generate_result_return(type_str: &str, call: TokenStream2) -> TokenStream2 {
1379 let ok_type = extract_result_ok(type_str).unwrap_or_default();
1380
1381 if ok_type == "()" || ok_type.is_empty() {
1382 quote! {
1383 let __result = #call;
1384 match __result {
1385 Ok(_) => {}
1386 Err(__e) => ring_error!(p, &format!("{}", __e)),
1387 }
1388 }
1389 } else if is_number_type(&ok_type) {
1390 quote! {
1391 let __result = #call;
1392 match __result {
1393 Ok(__val) => ring_ret_number!(p, __val as f64),
1394 Err(__e) => ring_error!(p, &format!("{}", __e)),
1395 }
1396 }
1397 } else if is_string_type(&ok_type) {
1398 quote! {
1399 let __result = #call;
1400 match __result {
1401 Ok(__val) => ring_ret_string!(p, &__val),
1402 Err(__e) => ring_error!(p, &format!("{}", __e)),
1403 }
1404 }
1405 } else if is_vec_type(&ok_type) {
1406 let vec_inner = extract_vec_inner(&ok_type).unwrap_or_default();
1407 if is_number_type(&vec_inner) {
1408 quote! {
1409 let __result = #call;
1410 match __result {
1411 Ok(__vec) => {
1412 let __list = ring_new_list!(p);
1413 for __item in __vec {
1414 ring_list_adddouble(__list, __item as f64);
1415 }
1416 ring_ret_list!(p, __list);
1417 }
1418 Err(__e) => ring_error!(p, &format!("{}", __e)),
1419 }
1420 }
1421 } else if is_string_type(&vec_inner) {
1422 quote! {
1423 let __result = #call;
1424 match __result {
1425 Ok(__vec) => {
1426 let __list = ring_new_list!(p);
1427 for __item in __vec {
1428 ring_list_addstring_str(__list, &__item);
1429 }
1430 ring_ret_list!(p, __list);
1431 }
1432 Err(__e) => ring_error!(p, &format!("{}", __e)),
1433 }
1434 }
1435 } else if is_struct_type(&vec_inner) {
1436 let type_const = struct_type_const(&extract_struct_name(&vec_inner));
1437 quote! {
1438 let __result = #call;
1439 match __result {
1440 Ok(__vec) => {
1441 let __list = ring_new_list!(p);
1442 for __item in __vec {
1443 let __ptr = Box::into_raw(Box::new(__item));
1444 ring_list_addcpointer(__list, __ptr as *mut std::ffi::c_void, #type_const);
1445 }
1446 ring_ret_list!(p, __list);
1447 }
1448 Err(__e) => ring_error!(p, &format!("{}", __e)),
1449 }
1450 }
1451 } else {
1452 quote! {
1453 let __result = #call;
1454 match __result {
1455 Ok(__vec) => {
1456 let __list = ring_new_list!(p);
1457 for __item in __vec {
1458 ring_list_adddouble(__list, __item as f64);
1459 }
1460 ring_ret_list!(p, __list);
1461 }
1462 Err(__e) => ring_error!(p, &format!("{}", __e)),
1463 }
1464 }
1465 }
1466 } else if is_struct_type(&ok_type) {
1467 let type_const = struct_type_const(&extract_struct_name(&ok_type));
1468 quote! {
1469 let __result = #call;
1470 match __result {
1471 Ok(__val) => {
1472 ring_ret_cpointer!(p, Box::into_raw(Box::new(__val)), #type_const);
1473 }
1474 Err(__e) => ring_error!(p, &format!("{}", __e)),
1475 }
1476 }
1477 } else {
1478 quote! {
1479 let __result = #call;
1480 match __result {
1481 Ok(__val) => ring_ret_number!(p, __val as f64),
1482 Err(__e) => ring_error!(p, &format!("{}", __e)),
1483 }
1484 }
1485 }
1486}
1487
1488fn generate_tuple_return(type_str: &str, call: TokenStream2) -> TokenStream2 {
1489 let elements = extract_tuple_elements(type_str);
1490
1491 if elements.is_empty() {
1492 return quote! { #call; };
1493 }
1494
1495 let mut add_statements = Vec::new();
1496
1497 for (i, elem_type) in elements.iter().enumerate() {
1498 let idx = syn::Index::from(i);
1499
1500 let add_stmt = if is_number_type(elem_type) {
1501 quote! { ring_list_adddouble(__list, __result.#idx as f64); }
1502 } else if is_string_type(elem_type) {
1503 quote! { ring_list_addstring_str(__list, &__result.#idx); }
1504 } else if elem_type == "bool" {
1505 quote! { ring_list_adddouble(__list, if __result.#idx { 1.0 } else { 0.0 }); }
1506 } else if is_struct_type(elem_type) {
1507 let type_const = struct_type_const(&extract_struct_name(elem_type));
1508 quote! {
1509 let __ptr = Box::into_raw(Box::new(__result.#idx));
1510 ring_list_addcpointer(__list, __ptr as *mut std::ffi::c_void, #type_const);
1511 }
1512 } else {
1513 quote! { ring_list_adddouble(__list, __result.#idx as f64); }
1514 };
1515
1516 add_statements.push(add_stmt);
1517 }
1518
1519 quote! {
1520 let __result = #call;
1521 let __list = ring_new_list!(p);
1522 #(#add_statements)*
1523 ring_ret_list!(p, __list);
1524 }
1525}
1526
1527fn generate_box_return(type_str: &str, call: TokenStream2) -> TokenStream2 {
1528 let inner = extract_box_inner(type_str).unwrap_or_default();
1529
1530 if is_number_type(&inner) {
1531 quote! {
1532 let __result = #call;
1533 ring_ret_number!(p, *__result as f64);
1534 }
1535 } else if is_string_type(&inner) {
1536 quote! {
1537 let __result = #call;
1538 ring_ret_string!(p, &*__result);
1539 }
1540 } else if inner == "bool" {
1541 quote! {
1542 let __result = #call;
1543 ring_ret_number!(p, if *__result { 1.0 } else { 0.0 });
1544 }
1545 } else if is_struct_type(&inner) {
1546 let type_const = struct_type_const(&extract_struct_name(&inner));
1547 quote! {
1548 let __result = #call;
1549 ring_ret_cpointer!(p, Box::into_raw(__result), #type_const);
1550 }
1551 } else {
1552 quote! {
1553 let __result = #call;
1554 ring_ret_number!(p, *__result as f64);
1555 }
1556 }
1557}
1558
1559fn generate_hashmap_return(type_str: &str, call: TokenStream2) -> TokenStream2 {
1560 let (key_type, value_type) = extract_hashmap_kv(type_str).unwrap_or_default();
1561
1562 let add_key = if is_number_type(&key_type) {
1563 quote! { ring_list_adddouble(__pair, __k as f64); }
1564 } else if is_string_type(&key_type) {
1565 quote! { ring_list_addstring_str(__pair, &__k); }
1566 } else {
1567 quote! { ring_list_addstring_str(__pair, &format!("{:?}", __k)); }
1568 };
1569
1570 let add_value = if is_number_type(&value_type) {
1571 quote! { ring_list_adddouble(__pair, __v as f64); }
1572 } else if is_string_type(&value_type) {
1573 quote! { ring_list_addstring_str(__pair, &__v); }
1574 } else if value_type == "bool" {
1575 quote! { ring_list_adddouble(__pair, if __v { 1.0 } else { 0.0 }); }
1576 } else if is_struct_type(&value_type) {
1577 let type_const = struct_type_const(&extract_struct_name(&value_type));
1578 quote! {
1579 let __ptr = Box::into_raw(Box::new(__v));
1580 ring_list_addcpointer(__pair, __ptr as *mut std::ffi::c_void, #type_const);
1581 }
1582 } else {
1583 quote! { ring_list_adddouble(__pair, __v as f64); }
1584 };
1585
1586 quote! {
1587 let __result = #call;
1588 let __list = ring_new_list!(p);
1589 for (__k, __v) in __result {
1590 let __pair = ring_list_newlist(__list);
1591 #add_key
1592 #add_value
1593 }
1594 ring_ret_list!(p, __list);
1595 }
1596}
1597
1598fn is_number_type(ty: &str) -> bool {
1599 let ty = ty.trim();
1600 matches!(
1601 ty,
1602 "i8" | "i16"
1603 | "i32"
1604 | "i64"
1605 | "i128"
1606 | "isize"
1607 | "u8"
1608 | "u16"
1609 | "u32"
1610 | "u64"
1611 | "u128"
1612 | "usize"
1613 | "f32"
1614 | "f64"
1615 )
1616}
1617
1618fn is_string_type(ty: &str) -> bool {
1619 let ty = ty.trim();
1620 ty == "String" || ty == "& str" || ty.contains("str")
1621}
1622
1623fn get_number_cast(ty: &str) -> TokenStream2 {
1624 let ty = ty.trim();
1625 match ty {
1626 "i8" => quote!(i8),
1627 "i16" => quote!(i16),
1628 "i32" => quote!(i32),
1629 "i64" => quote!(i64),
1630 "i128" => quote!(i128),
1631 "isize" => quote!(isize),
1632 "u8" => quote!(u8),
1633 "u16" => quote!(u16),
1634 "u32" => quote!(u32),
1635 "u64" => quote!(u64),
1636 "u128" => quote!(u128),
1637 "usize" => quote!(usize),
1638 "f32" => quote!(f32),
1639 "f64" => quote!(f64),
1640 _ => quote!(f64),
1641 }
1642}
1643
1644fn is_vec_type(ty: &str) -> bool {
1645 let ty = ty.trim();
1646 ty.starts_with("Vec <") || ty.starts_with("Vec<")
1647}
1648
1649fn is_option_type(ty: &str) -> bool {
1650 let ty = ty.trim();
1651 ty.starts_with("Option <") || ty.starts_with("Option<")
1652}
1653
1654fn is_result_type(ty: &str) -> bool {
1655 let ty = ty.trim();
1656 ty.starts_with("Result <") || ty.starts_with("Result<")
1657}
1658
1659fn is_tuple_type(ty: &str) -> bool {
1660 let ty = ty.trim();
1661 ty.starts_with('(') && ty.ends_with(')') && ty.contains(',')
1662}
1663
1664fn is_box_type(ty: &str) -> bool {
1665 let ty = ty.trim();
1666 ty.starts_with("Box <") || ty.starts_with("Box<")
1667}
1668
1669fn is_hashmap_type(ty: &str) -> bool {
1670 let ty = ty.trim();
1671 ty.starts_with("HashMap <")
1672 || ty.starts_with("HashMap<")
1673 || ty.starts_with("std :: collections :: HashMap")
1674 || ty.contains("HashMap <")
1675 || ty.contains("HashMap<")
1676}
1677
1678fn is_slice_type(ty: &str) -> bool {
1679 let ty = ty.trim();
1680 ty.starts_with("& [") || ty.starts_with("&[")
1681}
1682
1683fn is_struct_type(ty: &str) -> bool {
1684 let ty = ty.trim();
1685 let ty = ty.trim_start_matches('&').trim_start_matches("mut ").trim();
1686
1687 if is_vec_type(ty)
1688 || is_option_type(ty)
1689 || is_result_type(ty)
1690 || is_tuple_type(ty)
1691 || is_box_type(ty)
1692 || is_hashmap_type(ty)
1693 {
1694 return false;
1695 }
1696
1697 if is_number_type(ty) || is_string_type(ty) || ty == "bool" || ty == "()" {
1698 return false;
1699 }
1700
1701 ty.chars()
1702 .next()
1703 .map(|c| c.is_ascii_uppercase())
1704 .unwrap_or(false)
1705}
1706
1707fn is_struct_ref(ty: &str) -> bool {
1708 let ty = ty.trim();
1709 ty.starts_with('&') && is_struct_type(ty)
1710}
1711
1712fn extract_vec_inner(ty: &str) -> Option<String> {
1713 let ty = ty.trim();
1714 if ty.starts_with("Vec <") {
1715 Some(ty[5..ty.len() - 1].trim().to_string())
1716 } else if ty.starts_with("Vec<") {
1717 Some(ty[4..ty.len() - 1].trim().to_string())
1718 } else {
1719 None
1720 }
1721}
1722
1723fn extract_option_inner(ty: &str) -> Option<String> {
1724 let ty = ty.trim();
1725 if ty.starts_with("Option <") {
1726 Some(ty[8..ty.len() - 1].trim().to_string())
1727 } else if ty.starts_with("Option<") {
1728 Some(ty[7..ty.len() - 1].trim().to_string())
1729 } else {
1730 None
1731 }
1732}
1733
1734fn extract_result_ok(ty: &str) -> Option<String> {
1735 let ty = ty.trim();
1736 let inner = if ty.starts_with("Result <") {
1737 &ty[8..ty.len() - 1]
1738 } else if ty.starts_with("Result<") {
1739 &ty[7..ty.len() - 1]
1740 } else {
1741 return None;
1742 };
1743
1744 let mut depth = 0;
1745 for (i, c) in inner.char_indices() {
1746 match c {
1747 '<' => depth += 1,
1748 '>' => depth -= 1,
1749 ',' if depth == 0 => {
1750 return Some(inner[..i].trim().to_string());
1751 }
1752 _ => {}
1753 }
1754 }
1755 None
1756}
1757
1758fn extract_tuple_elements(ty: &str) -> Vec<String> {
1759 let ty = ty.trim();
1760 if !ty.starts_with('(') || !ty.ends_with(')') {
1761 return vec![];
1762 }
1763
1764 let inner = &ty[1..ty.len() - 1];
1765 let mut elements = vec![];
1766 let mut depth = 0;
1767 let mut start = 0;
1768
1769 for (i, c) in inner.char_indices() {
1770 match c {
1771 '<' | '(' => depth += 1,
1772 '>' | ')' => depth -= 1,
1773 ',' if depth == 0 => {
1774 elements.push(inner[start..i].trim().to_string());
1775 start = i + 1;
1776 }
1777 _ => {}
1778 }
1779 }
1780
1781 let last = inner[start..].trim();
1782 if !last.is_empty() {
1783 elements.push(last.to_string());
1784 }
1785
1786 elements
1787}
1788
1789fn extract_box_inner(ty: &str) -> Option<String> {
1790 let ty = ty.trim();
1791 if ty.starts_with("Box <") {
1792 Some(ty[5..ty.len() - 1].trim().to_string())
1793 } else if ty.starts_with("Box<") {
1794 Some(ty[4..ty.len() - 1].trim().to_string())
1795 } else {
1796 None
1797 }
1798}
1799
1800fn extract_hashmap_kv(ty: &str) -> Option<(String, String)> {
1801 let ty = ty.trim();
1802
1803 let hashmap_start = ty.find("HashMap")?;
1804 let rest = &ty[hashmap_start + 7..];
1805
1806 let angle_start = rest.find('<')?;
1807 let angle_end = rest.rfind('>')?;
1808 let inner = &rest[angle_start + 1..angle_end];
1809
1810 let mut depth = 0;
1811 for (i, c) in inner.char_indices() {
1812 match c {
1813 '<' => depth += 1,
1814 '>' => depth -= 1,
1815 ',' if depth == 0 => {
1816 let key = inner[..i].trim().to_string();
1817 let value = inner[i + 1..].trim().to_string();
1818 return Some((key, value));
1819 }
1820 _ => {}
1821 }
1822 }
1823 None
1824}
1825
1826fn extract_slice_inner(ty: &str) -> Option<String> {
1827 let ty = ty.trim();
1828 if ty.starts_with("& [") {
1829 Some(ty[3..ty.len() - 1].trim().to_string())
1830 } else if ty.starts_with("&[") {
1831 Some(ty[2..ty.len() - 1].trim().to_string())
1832 } else {
1833 None
1834 }
1835}
1836
1837fn extract_struct_name(ty: &str) -> String {
1838 ty.trim()
1839 .trim_start_matches('&')
1840 .trim()
1841 .trim_start_matches("mut ")
1842 .trim()
1843 .to_string()
1844}
1845
1846fn struct_type_const(struct_name: &str) -> syn::Ident {
1847 format_ident!("{}_TYPE", struct_name.to_uppercase())
1848}
1849
1850struct ParamBinding {
1851 check: TokenStream2,
1852 get: TokenStream2,
1853 arg: TokenStream2,
1854}
1855
1856fn is_mut_struct_ref(ty: &str) -> bool {
1857 let ty = ty.trim();
1858 ty.starts_with("& mut ") && is_struct_type(&ty[6..])
1859}
1860
1861fn generate_param_binding(name: &syn::Ident, ty: &Type, idx: i32) -> ParamBinding {
1862 let type_str = quote!(#ty).to_string();
1863
1864 if is_number_type(&type_str) {
1865 let cast = get_number_cast(&type_str);
1866 ParamBinding {
1867 check: quote! { ring_check_number!(p, #idx); },
1868 get: quote! { let #name = ring_get_number!(p, #idx) as #cast; },
1869 arg: quote! { #name },
1870 }
1871 } else if is_string_type(&type_str) {
1872 ParamBinding {
1873 check: quote! { ring_check_string!(p, #idx); },
1874 get: quote! { let #name = ring_get_string!(p, #idx); },
1875 arg: quote! { #name },
1876 }
1877 } else if type_str == "bool" {
1878 ParamBinding {
1879 check: quote! { ring_check_number!(p, #idx); },
1880 get: quote! { let #name = ring_get_number!(p, #idx) != 0.0; },
1881 arg: quote! { #name },
1882 }
1883 } else if is_mut_struct_ref(&type_str) {
1884 let struct_name_str = extract_struct_name(&type_str);
1885 let struct_ident = format_ident!("{}", struct_name_str);
1886 let type_const = struct_type_const(&struct_name_str);
1887 let ptr_name = format_ident!("__ptr_{}", name);
1888 ParamBinding {
1889 check: quote! { ring_check_cpointer!(p, #idx); },
1890 get: quote! { let #ptr_name = ring_get_cpointer!(p, #idx, #type_const); },
1891 arg: quote! { unsafe { &mut *(#ptr_name as *mut #struct_ident) } },
1892 }
1893 } else if is_struct_ref(&type_str) {
1894 let struct_name_str = extract_struct_name(&type_str);
1895 let struct_ident = format_ident!("{}", struct_name_str);
1896 let type_const = struct_type_const(&struct_name_str);
1897 let ptr_name = format_ident!("__ptr_{}", name);
1898 ParamBinding {
1899 check: quote! { ring_check_cpointer!(p, #idx); },
1900 get: quote! { let #ptr_name = ring_get_cpointer!(p, #idx, #type_const); },
1901 arg: quote! { unsafe { &*(#ptr_name as *const #struct_ident) } },
1902 }
1903 } else if is_vec_type(&type_str) {
1904 generate_vec_param_binding(name, &type_str, idx)
1905 } else if is_option_type(&type_str) {
1906 generate_option_param_binding(name, &type_str, idx)
1907 } else if is_slice_type(&type_str) {
1908 generate_slice_param_binding(name, &type_str, idx)
1909 } else if is_struct_type(&type_str) {
1910 let struct_name_str = extract_struct_name(&type_str);
1911 let struct_ident = format_ident!("{}", struct_name_str);
1912 let type_const = struct_type_const(&struct_name_str);
1913 let ptr_name = format_ident!("__ptr_{}", name);
1914 ParamBinding {
1915 check: quote! { ring_check_cpointer!(p, #idx); },
1916 get: quote! {
1917 let #ptr_name = ring_get_cpointer!(p, #idx, #type_const);
1918 let #name = unsafe { (*( #ptr_name as *const #struct_ident)).clone() };
1919 },
1920 arg: quote! { #name },
1921 }
1922 } else {
1923 ParamBinding {
1924 check: quote! { ring_check_number!(p, #idx); },
1925 get: quote! { let #name = ring_get_number!(p, #idx) as _; },
1926 arg: quote! { #name },
1927 }
1928 }
1929}
1930
1931fn generate_vec_param_binding(name: &syn::Ident, type_str: &str, idx: i32) -> ParamBinding {
1932 let inner = extract_vec_inner(type_str).unwrap_or_default();
1933
1934 if is_number_type(&inner) {
1935 let cast = get_number_cast(&inner);
1936 ParamBinding {
1937 check: quote! { ring_check_list!(p, #idx); },
1938 get: quote! {
1939 let __list = ring_get_list!(p, #idx);
1940 let __size = ring_list_getsize(__list);
1941 let mut #name = Vec::with_capacity(__size as usize);
1942 for __i in 1..=__size {
1943 if ring_list_isnumber(__list, __i) {
1944 #name.push(ring_list_getdouble(__list, __i) as #cast);
1945 }
1946 }
1947 },
1948 arg: quote! { #name },
1949 }
1950 } else if is_string_type(&inner) {
1951 ParamBinding {
1952 check: quote! { ring_check_list!(p, #idx); },
1953 get: quote! {
1954 let __list = ring_get_list!(p, #idx);
1955 let __size = ring_list_getsize(__list);
1956 let mut #name = Vec::with_capacity(__size as usize);
1957 for __i in 1..=__size {
1958 if ring_list_isstring(__list, __i) {
1959 let __cstr = ring_list_getstring(__list, __i);
1960 let __s = unsafe { std::ffi::CStr::from_ptr(__cstr).to_string_lossy().into_owned() };
1961 #name.push(__s);
1962 }
1963 }
1964 },
1965 arg: quote! { #name },
1966 }
1967 } else if is_struct_type(&inner) {
1968 let inner_struct_name = extract_struct_name(&inner);
1969 let inner_struct_ident = format_ident!("{}", inner_struct_name);
1970 ParamBinding {
1971 check: quote! { ring_check_list!(p, #idx); },
1972 get: quote! {
1973 let __list = ring_get_list!(p, #idx);
1974 let __size = ring_list_getsize(__list);
1975 let mut #name = Vec::with_capacity(__size as usize);
1976 for __i in 1..=__size {
1977 let __ptr = if ring_list_ispointer(__list, __i) {
1978 ring_list_getpointer(__list, __i)
1979 } else if ring_list_islist(__list, __i) {
1980 let __inner_list = ring_list_getlist(__list, __i);
1981 if ring_list_ispointer(__inner_list, 1) {
1982 ring_list_getpointer(__inner_list, 1)
1983 } else {
1984 std::ptr::null_mut()
1985 }
1986 } else {
1987 std::ptr::null_mut()
1988 };
1989 if !__ptr.is_null() {
1990 let __item = unsafe { &*(__ptr as *const #inner_struct_ident) };
1991 #name.push(__item.clone());
1992 }
1993 }
1994 },
1995 arg: quote! { #name },
1996 }
1997 } else {
1998 let cast = get_number_cast(&inner);
1999 ParamBinding {
2000 check: quote! { ring_check_list!(p, #idx); },
2001 get: quote! {
2002 let __list = ring_get_list!(p, #idx);
2003 let __size = ring_list_getsize(__list);
2004 let mut #name = Vec::with_capacity(__size as usize);
2005 for __i in 1..=__size {
2006 if ring_list_isnumber(__list, __i) {
2007 #name.push(ring_list_getdouble(__list, __i) as #cast);
2008 }
2009 }
2010 },
2011 arg: quote! { #name },
2012 }
2013 }
2014}
2015
2016fn generate_option_param_binding(name: &syn::Ident, type_str: &str, idx: i32) -> ParamBinding {
2017 let inner = extract_option_inner(type_str).unwrap_or_default();
2018
2019 if is_number_type(&inner) {
2020 let cast = get_number_cast(&inner);
2021 ParamBinding {
2022 check: quote! {},
2023 get: quote! {
2024 let #name = if ring_api_isstring(p, #idx) {
2025 let __s = ring_get_string!(p, #idx);
2026 if __s.is_empty() { None } else { None }
2027 } else if ring_api_isnumber(p, #idx) {
2028 Some(ring_get_number!(p, #idx) as #cast)
2029 } else {
2030 None
2031 };
2032 },
2033 arg: quote! { #name },
2034 }
2035 } else if is_string_type(&inner) {
2036 ParamBinding {
2037 check: quote! {},
2038 get: quote! {
2039 let #name = if ring_api_isstring(p, #idx) {
2040 let __s = ring_get_string!(p, #idx);
2041 if __s.is_empty() { None } else { Some(__s.to_string()) }
2042 } else {
2043 None
2044 };
2045 },
2046 arg: quote! { #name },
2047 }
2048 } else if is_struct_type(&inner) {
2049 let inner_struct_name = extract_struct_name(&inner);
2050 let inner_struct_ident = format_ident!("{}", inner_struct_name);
2051 let inner_type_const = struct_type_const(&inner_struct_name);
2052 ParamBinding {
2053 check: quote! {},
2054 get: quote! {
2055 let #name = if ring_api_isstring(p, #idx) {
2056 None
2057 } else if ring_api_ispointer(p, #idx) {
2058 let __ptr = ring_get_cpointer!(p, #idx, #inner_type_const);
2059 if __ptr.is_null() {
2060 None
2061 } else {
2062 Some(unsafe { (*(__ptr as *const #inner_struct_ident)).clone() })
2063 }
2064 } else {
2065 None
2066 };
2067 },
2068 arg: quote! { #name },
2069 }
2070 } else {
2071 let cast = get_number_cast(&inner);
2072 ParamBinding {
2073 check: quote! {},
2074 get: quote! {
2075 let #name = if ring_api_isstring(p, #idx) {
2076 None
2077 } else if ring_api_isnumber(p, #idx) {
2078 Some(ring_get_number!(p, #idx) as #cast)
2079 } else {
2080 None
2081 };
2082 },
2083 arg: quote! { #name },
2084 }
2085 }
2086}
2087
2088fn generate_slice_param_binding(name: &syn::Ident, type_str: &str, idx: i32) -> ParamBinding {
2089 let inner = extract_slice_inner(type_str).unwrap_or_default();
2090 let vec_name = format_ident!("__{}_vec", name);
2091
2092 if is_number_type(&inner) {
2093 let cast = get_number_cast(&inner);
2094 ParamBinding {
2095 check: quote! { ring_check_list!(p, #idx); },
2096 get: quote! {
2097 let __list = ring_get_list!(p, #idx);
2098 let __size = ring_list_getsize(__list);
2099 let mut #vec_name: Vec<#cast> = Vec::with_capacity(__size as usize);
2100 for __i in 1..=__size {
2101 if ring_list_isnumber(__list, __i) {
2102 #vec_name.push(ring_list_getdouble(__list, __i) as #cast);
2103 }
2104 }
2105 },
2106 arg: quote! { &#vec_name[..] },
2107 }
2108 } else if is_string_type(&inner) {
2109 ParamBinding {
2110 check: quote! { ring_check_list!(p, #idx); },
2111 get: quote! {
2112 let __list = ring_get_list!(p, #idx);
2113 let __size = ring_list_getsize(__list);
2114 let mut #vec_name: Vec<String> = Vec::with_capacity(__size as usize);
2115 for __i in 1..=__size {
2116 if ring_list_isstring(__list, __i) {
2117 let __cstr = ring_list_getstring(__list, __i);
2118 let __s = unsafe { std::ffi::CStr::from_ptr(__cstr).to_string_lossy().into_owned() };
2119 #vec_name.push(__s);
2120 }
2121 }
2122 },
2123 arg: quote! { &#vec_name[..] },
2124 }
2125 } else if is_struct_type(&inner) {
2126 let inner_struct_name = extract_struct_name(&inner);
2127 let inner_struct_ident = format_ident!("{}", inner_struct_name);
2128 ParamBinding {
2129 check: quote! { ring_check_list!(p, #idx); },
2130 get: quote! {
2131 let __list = ring_get_list!(p, #idx);
2132 let __size = ring_list_getsize(__list);
2133 let mut #vec_name: Vec<#inner_struct_ident> = Vec::with_capacity(__size as usize);
2134 for __i in 1..=__size {
2135 let __ptr = if ring_list_ispointer(__list, __i) {
2136 ring_list_getpointer(__list, __i)
2137 } else {
2138 std::ptr::null_mut()
2139 };
2140 if !__ptr.is_null() {
2141 let __item = unsafe { &*(__ptr as *const #inner_struct_ident) };
2142 #vec_name.push(__item.clone());
2143 }
2144 }
2145 },
2146 arg: quote! { &#vec_name[..] },
2147 }
2148 } else {
2149 ParamBinding {
2150 check: quote! { ring_check_list!(p, #idx); },
2151 get: quote! {
2152 let __list = ring_get_list!(p, #idx);
2153 let __size = ring_list_getsize(__list);
2154 let mut #vec_name: Vec<f64> = Vec::with_capacity(__size as usize);
2155 for __i in 1..=__size {
2156 if ring_list_isnumber(__list, __i) {
2157 #vec_name.push(ring_list_getdouble(__list, __i));
2158 }
2159 }
2160 },
2161 arg: quote! { &#vec_name[..] },
2162 }
2163 }
2164}