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