mirror of
git://git.proxmox.com/git/perlmod.git
synced 2025-01-04 13:17:39 +03:00
macro: expose the 'cv' as parameter on exports
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
c7882155cf
commit
77171723e3
@ -112,6 +112,7 @@ pub struct FunctionAttrs {
|
||||
pub perl_name: Option<Ident>,
|
||||
pub xs_name: Option<Ident>,
|
||||
pub raw_return: bool,
|
||||
pub cv_variable: Option<Ident>,
|
||||
pub prototype: Option<String>,
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ use proc_macro2::{Ident, Span, TokenStream};
|
||||
|
||||
use quote::quote;
|
||||
use syn::Error;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
use crate::attribs::FunctionAttrs;
|
||||
|
||||
@ -15,7 +16,13 @@ pub struct XSub {
|
||||
|
||||
#[derive(Default)]
|
||||
struct ArgumentAttrs {
|
||||
/// This is the `CV` pointer.
|
||||
cv: Option<Span>,
|
||||
|
||||
/// Skip the deserializer for this argument.
|
||||
raw: bool,
|
||||
|
||||
/// Call `TryFrom<&Value>::try_from` for this argument instead of deserializing it.
|
||||
try_from_ref: bool,
|
||||
}
|
||||
|
||||
@ -25,6 +32,8 @@ impl ArgumentAttrs {
|
||||
self.raw = true;
|
||||
} else if path.is_ident("try_from_ref") {
|
||||
self.try_from_ref = true;
|
||||
} else if path.is_ident("cv") {
|
||||
self.cv = Some(path.span());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -33,10 +42,10 @@ impl ArgumentAttrs {
|
||||
}
|
||||
|
||||
fn validate(&self, span: Span) -> Result<(), Error> {
|
||||
if self.raw && self.try_from_ref {
|
||||
if self.raw as usize + self.try_from_ref as usize + self.cv.is_some() as usize > 1 {
|
||||
bail!(
|
||||
span,
|
||||
"`raw` and `try_from_ref` attributes are mutually exclusive"
|
||||
"`raw` and `try_from_ref` and `cv` attributes are mutually exclusive"
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
@ -83,6 +92,7 @@ pub fn handle_function(
|
||||
let mut extract_arguments = TokenStream::new();
|
||||
let mut deserialized_arguments = TokenStream::new();
|
||||
let mut passed_arguments = TokenStream::new();
|
||||
let mut cv_arg_param = TokenStream::new();
|
||||
for arg in &mut func.sig.inputs {
|
||||
let mut argument_attrs = ArgumentAttrs::default();
|
||||
|
||||
@ -91,7 +101,6 @@ pub fn handle_function(
|
||||
syn::FnArg::Typed(ref mut pt) => {
|
||||
pt.attrs
|
||||
.retain(|attr| !argument_attrs.handle_path(&attr.path));
|
||||
use syn::spanned::Spanned;
|
||||
argument_attrs.validate(pt.span())?;
|
||||
&*pt
|
||||
}
|
||||
@ -112,6 +121,19 @@ pub fn handle_function(
|
||||
|
||||
let arg_type = &*pat_ty.ty;
|
||||
|
||||
if let Some(cv_span) = argument_attrs.cv {
|
||||
if !cv_arg_param.is_empty() {
|
||||
bail!(cv_span, "only 1 'cv' parameter allowed");
|
||||
}
|
||||
cv_arg_param = quote! { #arg_name: #arg_type };
|
||||
if passed_arguments.is_empty() {
|
||||
passed_arguments.extend(quote! { #arg_name });
|
||||
} else {
|
||||
passed_arguments.extend(quote! {, #arg_name });
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let extracted_name = Ident::new(&format!("extracted_arg_{}", arg_name), arg_name.span());
|
||||
let deserialized_name =
|
||||
Ident::new(&format!("deserialized_arg_{}", arg_name), arg_name.span());
|
||||
@ -193,7 +215,7 @@ pub fn handle_function(
|
||||
&format!(
|
||||
"too many parameters for function '{}', (expected {})\n",
|
||||
name,
|
||||
func.sig.inputs.len()
|
||||
func.sig.inputs.len() - (!cv_arg_param.is_empty()) as usize
|
||||
),
|
||||
Span::call_site(),
|
||||
);
|
||||
@ -210,6 +232,7 @@ pub fn handle_function(
|
||||
&impl_xs_name,
|
||||
passed_arguments,
|
||||
export_public,
|
||||
!cv_arg_param.is_empty(),
|
||||
)?;
|
||||
|
||||
let tokens = quote! {
|
||||
@ -219,7 +242,7 @@ pub fn handle_function(
|
||||
|
||||
#[inline(never)]
|
||||
#[allow(non_snake_case)]
|
||||
fn #impl_xs_name() -> Result<#return_type, *mut ::perlmod::ffi::SV> {
|
||||
fn #impl_xs_name(#cv_arg_param) -> Result<#return_type, *mut ::perlmod::ffi::SV> {
|
||||
let argmark = unsafe { ::perlmod::ffi::pop_arg_mark() };
|
||||
let mut args = argmark.iter();
|
||||
|
||||
@ -285,6 +308,7 @@ fn handle_return_kind(
|
||||
impl_xs_name: &Ident,
|
||||
passed_arguments: TokenStream,
|
||||
export_public: Option<&syn::Visibility>,
|
||||
cv_arg: bool,
|
||||
) -> Result<ReturnHandling, Error> {
|
||||
let return_type;
|
||||
let mut handle_return;
|
||||
@ -295,6 +319,12 @@ fn handle_return_kind(
|
||||
None => quote! { #[allow(non_snake_case)] },
|
||||
};
|
||||
|
||||
let (cv_arg_name, cv_arg_passed) = if cv_arg {
|
||||
(quote! { cv }, quote! { cv })
|
||||
} else {
|
||||
(quote! { _cv }, TokenStream::new())
|
||||
};
|
||||
|
||||
let pthx = crate::pthx_param();
|
||||
match ret {
|
||||
Return::None(result) => {
|
||||
@ -327,9 +357,9 @@ fn handle_return_kind(
|
||||
|
||||
wrapper_func = quote! {
|
||||
#[doc(hidden)]
|
||||
#vis extern "C" fn #xs_name(#pthx _cv: &::perlmod::ffi::CV) {
|
||||
#vis extern "C" fn #xs_name(#pthx #cv_arg_name: &::perlmod::ffi::CV) {
|
||||
unsafe {
|
||||
match #impl_xs_name() {
|
||||
match #impl_xs_name(#cv_arg_passed) {
|
||||
Ok(()) => (),
|
||||
Err(sv) => ::perlmod::ffi::croak(sv),
|
||||
}
|
||||
@ -374,9 +404,9 @@ fn handle_return_kind(
|
||||
|
||||
wrapper_func = quote! {
|
||||
#[doc(hidden)]
|
||||
#vis extern "C" fn #xs_name(#pthx _cv: &::perlmod::ffi::CV) {
|
||||
#vis extern "C" fn #xs_name(#pthx #cv_arg_name: &::perlmod::ffi::CV) {
|
||||
unsafe {
|
||||
match #impl_xs_name() {
|
||||
match #impl_xs_name(#cv_arg_passed) {
|
||||
Ok(sv) => ::perlmod::ffi::stack_push_raw(sv),
|
||||
Err(sv) => ::perlmod::ffi::croak(sv),
|
||||
}
|
||||
@ -460,9 +490,9 @@ fn handle_return_kind(
|
||||
|
||||
wrapper_func = quote! {
|
||||
#[doc(hidden)]
|
||||
#vis extern "C" fn #xs_name(#pthx _cv: &::perlmod::ffi::CV) {
|
||||
#vis extern "C" fn #xs_name(#pthx #cv_arg_name: &::perlmod::ffi::CV) {
|
||||
unsafe {
|
||||
match #impl_xs_name() {
|
||||
match #impl_xs_name(#cv_arg_passed) {
|
||||
Ok(sv) => { #push },
|
||||
Err(sv) => ::perlmod::ffi::croak(sv),
|
||||
}
|
||||
|
@ -75,6 +75,11 @@ mod export {
|
||||
fn test_trailing_optional(first: u32, second: Option<u32>) {
|
||||
println!("{:?}, {:?}", first, second);
|
||||
}
|
||||
|
||||
#[export(xs_name = "testit_xsub")]
|
||||
fn testit(#[cv] cv: &perlmod::ffi::CV, arg: &str) {
|
||||
let _ = (cv, arg);
|
||||
}
|
||||
}
|
||||
|
||||
#[perlmod::package(name = "RSPM::EnvVarLibrary", lib = "x-${CARGO_PKG_NAME}-y")]
|
||||
|
Loading…
Reference in New Issue
Block a user