1use proc_macro::TokenStream;
135use proc_macro2::TokenStream as TokenStream2;
136use quote::{format_ident, quote};
137use std::collections::HashSet;
138use syn::parse::{Parse, ParseStream};
139use syn::{
140 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#[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}