Skip to main content

ring_lang_codegen/
lib.rs

1//! # ring-lang-codegen
2//!
3//! Proc macros to generate [Ring](https://ring-lang.github.io/) programming language
4//! extensions in Rust with zero configuration.
5//!
6//! ## Features
7//!
8//! - **Zero config** - Just use the `ring_extension!` macro, no separate config files
9//! - **Auto-generated bindings** - Structs, impl blocks, and functions are automatically wrapped
10//! - **Auto ring_libinit!** - Library registration is generated for you
11//! - **Full IDE support** - Works with rust-analyzer, autocomplete, and type checking
12//!
13//! ## Quick Start
14//!
15//! Add to your `Cargo.toml`:
16//!
17//! ```toml
18//! [lib]
19//! crate-type = ["cdylib"]
20//!
21//! [dependencies]
22//! ring-lang-rs = "0.1"
23//! ring-lang-codegen = "0.1"
24//! ```
25//!
26//! ## Usage
27//!
28//! ```rust,ignore
29//! use ring_lang_codegen::ring_extension;
30//! use ring_lang_rs::*;
31//!
32//! ring_extension! {
33//!     prefix: "mylib";  // Optional prefix for all functions
34//!
35//!     // Standalone functions - generates mylib_add(a, b)
36//!     pub fn add(a: i32, b: i32) -> i32 {
37//!         a + b
38//!     }
39//!
40//!     pub fn greet(name: &str) -> String {
41//!         format!("Hello, {}!", name)
42//!     }
43//!
44//!     // Structs with auto-generated accessors
45//!     #[derive(Default)]
46//!     pub struct Counter {
47//!         pub value: i64,
48//!         pub name: String,
49//!     }
50//!
51//!     // Impl blocks with methods
52//!     impl Counter {
53//!         pub fn new(name: &str, initial: i64) -> Self {
54//!             Counter { value: initial, name: name.to_string() }
55//!         }
56//!
57//!         pub fn increment(&mut self) {
58//!             self.value += 1;
59//!         }
60//!
61//!         pub fn get_value(&self) -> i64 {
62//!             self.value
63//!         }
64//!     }
65//! }
66//! ```
67//!
68//! ## What Gets Generated
69//!
70//! | Source | Generated Ring Functions |
71//! |--------|--------------------------|
72//! | `pub fn add(a, b)` | `mylib_add(a, b)` |
73//! | `pub struct Counter` | `mylib_counter_new()`, `mylib_counter_delete(ptr)` |
74//! | `pub value: i64` field | `mylib_counter_get_value(ptr)`, `mylib_counter_set_value(ptr, v)` |
75//! | `impl Counter { pub fn new() }` | Replaces default `_new` with custom constructor |
76//! | `pub fn increment(&mut self)` | `mylib_counter_increment(ptr)` |
77//!
78//! ## Ring Usage
79//!
80//! ```ring
81//! loadlib("libmylib.so")  # or .dll / .dylib
82//!
83//! ? mylib_add(10, 20)        # 30
84//! ? mylib_greet("World")     # Hello, World!
85//!
86//! obj = mylib_counter_new("test", 0)
87//! mylib_counter_increment(obj)
88//! ? mylib_counter_get_value(obj)  # 1
89//! mylib_counter_delete(obj)
90//! ```
91//!
92//! ## Supported Types
93//!
94//! ### Return Types
95//!
96//! | Rust Type | Ring Representation |
97//! |-----------|---------------------|
98//! | `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `f32`, `f64` | Number |
99//! | `bool` | Number (1 or 0) |
100//! | `String`, `&str` | String |
101//! | `Vec<T>` | List |
102//! | `Vec<Vec<T>>` | Nested list (2D array) |
103//! | `Option<T>` | Value or empty string for None |
104//! | `Result<T, E>` | Value on Ok, Ring error on Err |
105//! | `(A, B)`, `(A, B, C)` | List (tuple as list) |
106//! | `Box<T>` | Unwrapped inner value |
107//! | `HashMap<K, V>` | List of `[key, value]` pairs |
108//! | Custom structs | C pointer |
109//!
110//! ### Parameter Types
111//!
112//! | Rust Type | Ring Input |
113//! |-----------|------------|
114//! | `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `f32`, `f64` | Number |
115//! | `bool` | Number (non-zero = true) |
116//! | `&str`, `String` | String |
117//! | `&T` (struct reference) | C pointer |
118//! | `&mut T` (mutable struct reference) | C pointer |
119//! | `Vec<T>` | List |
120//! | `&[T]` (slice) | List |
121//! | `Option<T>` | Value or empty string for None |
122//! | Custom structs | C pointer |
123//!
124//! ### Field Types (Getters/Setters)
125//!
126//! | Rust Type | Get Returns | Set Accepts |
127//! |-----------|-------------|-------------|
128//! | Primitives | Number | Number |
129//! | `String` | String | String |
130//! | `Vec<T>` | List | List |
131//! | `Option<T>` | Value or empty string | Value or empty string |
132//! | Struct | C pointer | C pointer |
133
134use 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    parse_macro_input, FnArg, Ident, ImplItem, ImplItemFn, Item, ItemFn, ItemImpl, ItemStruct, Pat,
141    ReturnType, Token, Type, Visibility,
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/// Define a Ring module with auto-generated bindings and ring_libinit!
175#[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 => ring_ret_string!(p, ""),
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 => ring_ret_string!(p, ""),
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 => ring_ret_string!(p, ""),
567                }
568            }
569        } else {
570            quote! {
571                match &obj.#field_name {
572                    Some(__val) => ring_ret_number!(p, *__val as f64),
573                    None => ring_ret_string!(p, ""),
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_addstring(__list, b"\0"),
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_addstring(__list, b"\0"),
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_addstring(__list, b"\0"),
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_addstring(__list, b"\0"),
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 => ring_ret_string!(p, ""),
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 => ring_ret_string!(p, ""),
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 => ring_ret_string!(p, ""),
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 => ring_ret_string!(p, ""),
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 => ring_ret_string!(p, ""),
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 => ring_ret_string!(p, ""),
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 => ring_ret_string!(p, ""),
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 => ring_ret_string!(p, ""),
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}