macros: change self_arg to be an expression
This commit is contained in:
parent
b89934475d
commit
52cd9cbc90
|
@ -8,7 +8,7 @@ use quote::ToTokens;
|
||||||
use quote::{quote, quote_spanned};
|
use quote::{quote, quote_spanned};
|
||||||
use syn::ext::IdentExt;
|
use syn::ext::IdentExt;
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::{Result, Token};
|
use syn::Result;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct FnArg<'a> {
|
pub struct FnArg<'a> {
|
||||||
|
@ -100,38 +100,31 @@ pub enum FnType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FnType {
|
impl FnType {
|
||||||
pub fn self_conversion(
|
pub fn self_arg(&self, cls: Option<&syn::Type>, error_mode: ExtractErrorMode) -> TokenStream {
|
||||||
&self,
|
|
||||||
cls: Option<&syn::Type>,
|
|
||||||
error_mode: ExtractErrorMode,
|
|
||||||
) -> TokenStream {
|
|
||||||
match self {
|
match self {
|
||||||
FnType::Getter(st) | FnType::Setter(st) | FnType::Fn(st) => st.receiver(
|
FnType::Getter(st) | FnType::Setter(st) | FnType::Fn(st) => {
|
||||||
cls.expect("no class given for Fn with a \"self\" receiver"),
|
let mut receiver = st.receiver(
|
||||||
error_mode,
|
cls.expect("no class given for Fn with a \"self\" receiver"),
|
||||||
),
|
error_mode,
|
||||||
|
);
|
||||||
|
syn::Token![,](Span::call_site()).to_tokens(&mut receiver);
|
||||||
|
receiver
|
||||||
|
}
|
||||||
FnType::FnNew | FnType::FnStatic | FnType::ClassAttribute => {
|
FnType::FnNew | FnType::FnStatic | FnType::ClassAttribute => {
|
||||||
quote!()
|
quote!()
|
||||||
}
|
}
|
||||||
FnType::FnClass | FnType::FnNewClass => {
|
FnType::FnClass | FnType::FnNewClass => {
|
||||||
quote! {
|
quote! {
|
||||||
let _slf = _pyo3::types::PyType::from_type_ptr(_py, _slf as *mut _pyo3::ffi::PyTypeObject);
|
_pyo3::types::PyType::from_type_ptr(_py, _slf as *mut _pyo3::ffi::PyTypeObject),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FnType::FnModule => {
|
FnType::FnModule => {
|
||||||
quote! {
|
quote! {
|
||||||
let _slf = _py.from_borrowed_ptr::<_pyo3::types::PyModule>(_slf);
|
_py.from_borrowed_ptr::<_pyo3::types::PyModule>(_slf),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn self_arg(&self) -> TokenStream {
|
|
||||||
match self {
|
|
||||||
FnType::FnNew | FnType::FnStatic | FnType::ClassAttribute => quote!(),
|
|
||||||
_ => quote!(_slf,),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -166,40 +159,34 @@ impl SelfType {
|
||||||
let _slf = syn::Ident::new("_slf", Span::call_site());
|
let _slf = syn::Ident::new("_slf", Span::call_site());
|
||||||
match self {
|
match self {
|
||||||
SelfType::Receiver { span, mutable } => {
|
SelfType::Receiver { span, mutable } => {
|
||||||
let (method, mutability) = if *mutable {
|
let method = if *mutable {
|
||||||
(
|
syn::Ident::new("extract_pyclass_ref_mut", *span)
|
||||||
quote_spanned! { *span => extract_pyclass_ref_mut },
|
|
||||||
Some(Token![mut](*span)),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
(quote_spanned! { *span => extract_pyclass_ref }, None)
|
syn::Ident::new("extract_pyclass_ref", *span)
|
||||||
};
|
};
|
||||||
let extract = error_mode.handle_error(
|
error_mode.handle_error(
|
||||||
&py,
|
&py,
|
||||||
quote_spanned! { *span =>
|
quote_spanned! { *span =>
|
||||||
_pyo3::impl_::extract_argument::#method(
|
_pyo3::impl_::extract_argument::#method::<#cls>(
|
||||||
#py.from_borrowed_ptr::<_pyo3::PyAny>(#_slf),
|
#py.from_borrowed_ptr::<_pyo3::PyAny>(#_slf),
|
||||||
&mut holder,
|
&mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT },
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
quote_spanned! { *span =>
|
|
||||||
let mut holder = _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT;
|
|
||||||
let #_slf: &#mutability #cls = #extract;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
SelfType::TryFromPyCell(span) => {
|
SelfType::TryFromPyCell(span) => {
|
||||||
let cell = error_mode.handle_error(
|
error_mode.handle_error(
|
||||||
&py,
|
&py,
|
||||||
quote!{
|
quote_spanned! { *span =>
|
||||||
_py.from_borrowed_ptr::<_pyo3::PyAny>(_slf).downcast::<_pyo3::PyCell<#cls>>()
|
#py.from_borrowed_ptr::<_pyo3::PyAny>(#_slf).downcast::<_pyo3::PyCell<#cls>>()
|
||||||
|
.map_err(::std::convert::Into::<_pyo3::PyErr>::into)
|
||||||
|
.and_then(
|
||||||
|
#[allow(clippy::useless_conversion)] // In case _slf is PyCell<Self>
|
||||||
|
|cell| ::std::convert::TryFrom::try_from(cell).map_err(::std::convert::Into::into)
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
quote_spanned! { *span =>
|
|
||||||
let _cell = #cell;
|
|
||||||
#[allow(clippy::useless_conversion)] // In case _slf is PyCell<Self>
|
|
||||||
let #_slf = ::std::convert::TryFrom::try_from(_cell)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,8 +408,7 @@ impl<'a> FnSpec<'a> {
|
||||||
ident: &proc_macro2::Ident,
|
ident: &proc_macro2::Ident,
|
||||||
cls: Option<&syn::Type>,
|
cls: Option<&syn::Type>,
|
||||||
) -> Result<TokenStream> {
|
) -> Result<TokenStream> {
|
||||||
let self_conversion = self.tp.self_conversion(cls, ExtractErrorMode::Raise);
|
let self_arg = self.tp.self_arg(cls, ExtractErrorMode::Raise);
|
||||||
let self_arg = self.tp.self_arg();
|
|
||||||
let py = syn::Ident::new("_py", Span::call_site());
|
let py = syn::Ident::new("_py", Span::call_site());
|
||||||
let func_name = &self.name;
|
let func_name = &self.name;
|
||||||
|
|
||||||
|
@ -448,13 +434,13 @@ impl<'a> FnSpec<'a> {
|
||||||
} else {
|
} else {
|
||||||
rust_call(vec![])
|
rust_call(vec![])
|
||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
unsafe fn #ident<'py>(
|
unsafe fn #ident<'py>(
|
||||||
#py: _pyo3::Python<'py>,
|
#py: _pyo3::Python<'py>,
|
||||||
_slf: *mut _pyo3::ffi::PyObject,
|
_slf: *mut _pyo3::ffi::PyObject,
|
||||||
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
||||||
let function = #rust_name; // Shadow the function name to avoid #3017
|
let function = #rust_name; // Shadow the function name to avoid #3017
|
||||||
#self_conversion
|
|
||||||
#call
|
#call
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,7 +457,6 @@ impl<'a> FnSpec<'a> {
|
||||||
_kwnames: *mut _pyo3::ffi::PyObject
|
_kwnames: *mut _pyo3::ffi::PyObject
|
||||||
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
||||||
let function = #rust_name; // Shadow the function name to avoid #3017
|
let function = #rust_name; // Shadow the function name to avoid #3017
|
||||||
#self_conversion
|
|
||||||
#arg_convert
|
#arg_convert
|
||||||
#call
|
#call
|
||||||
}
|
}
|
||||||
|
@ -488,7 +473,6 @@ impl<'a> FnSpec<'a> {
|
||||||
_kwargs: *mut _pyo3::ffi::PyObject
|
_kwargs: *mut _pyo3::ffi::PyObject
|
||||||
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
||||||
let function = #rust_name; // Shadow the function name to avoid #3017
|
let function = #rust_name; // Shadow the function name to avoid #3017
|
||||||
#self_conversion
|
|
||||||
#arg_convert
|
#arg_convert
|
||||||
#call
|
#call
|
||||||
}
|
}
|
||||||
|
|
|
@ -475,8 +475,13 @@ fn impl_py_class_attribute(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<Me
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impl_call_setter(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<TokenStream> {
|
fn impl_call_setter(
|
||||||
|
cls: &syn::Type,
|
||||||
|
spec: &FnSpec<'_>,
|
||||||
|
self_type: &SelfType,
|
||||||
|
) -> syn::Result<TokenStream> {
|
||||||
let (py_arg, args) = split_off_python_arg(&spec.signature.arguments);
|
let (py_arg, args) = split_off_python_arg(&spec.signature.arguments);
|
||||||
|
let slf = self_type.receiver(cls, ExtractErrorMode::Raise);
|
||||||
|
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
bail_spanned!(spec.name.span() => "setter function expected to have one argument");
|
bail_spanned!(spec.name.span() => "setter function expected to have one argument");
|
||||||
|
@ -489,9 +494,9 @@ fn impl_call_setter(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<TokenStre
|
||||||
|
|
||||||
let name = &spec.name;
|
let name = &spec.name;
|
||||||
let fncall = if py_arg.is_some() {
|
let fncall = if py_arg.is_some() {
|
||||||
quote!(#cls::#name(_slf, _py, _val))
|
quote!(#cls::#name(#slf, _py, _val))
|
||||||
} else {
|
} else {
|
||||||
quote!(#cls::#name(_slf, _val))
|
quote!(#cls::#name(#slf, _val))
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(fncall)
|
Ok(fncall)
|
||||||
|
@ -506,31 +511,25 @@ pub fn impl_py_setter_def(
|
||||||
let doc = property_type.doc();
|
let doc = property_type.doc();
|
||||||
let setter_impl = match property_type {
|
let setter_impl = match property_type {
|
||||||
PropertyType::Descriptor {
|
PropertyType::Descriptor {
|
||||||
field: syn::Field {
|
field_index, field, ..
|
||||||
ident: Some(ident), ..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
// named struct field
|
let slf = SelfType::Receiver {
|
||||||
quote!({ _slf.#ident = _val; })
|
mutable: true,
|
||||||
}
|
span: Span::call_site(),
|
||||||
PropertyType::Descriptor { field_index, .. } => {
|
}
|
||||||
// tuple struct field
|
.receiver(cls, ExtractErrorMode::Raise);
|
||||||
let index = syn::Index::from(field_index);
|
if let Some(ident) = &field.ident {
|
||||||
quote!({ _slf.#index = _val; })
|
// named struct field
|
||||||
}
|
quote!({ #slf.#ident = _val; })
|
||||||
PropertyType::Function { spec, .. } => impl_call_setter(cls, spec)?,
|
} else {
|
||||||
};
|
// tuple struct field
|
||||||
|
let index = syn::Index::from(field_index);
|
||||||
let slf = match property_type {
|
quote!({ #slf.#index = _val; })
|
||||||
PropertyType::Descriptor { .. } => SelfType::Receiver {
|
}
|
||||||
mutable: true,
|
|
||||||
span: Span::call_site(),
|
|
||||||
}
|
|
||||||
.receiver(cls, ExtractErrorMode::Raise),
|
|
||||||
PropertyType::Function { self_type, .. } => {
|
|
||||||
self_type.receiver(cls, ExtractErrorMode::Raise)
|
|
||||||
}
|
}
|
||||||
|
PropertyType::Function {
|
||||||
|
spec, self_type, ..
|
||||||
|
} => impl_call_setter(cls, spec, self_type)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let wrapper_ident = match property_type {
|
let wrapper_ident = match property_type {
|
||||||
|
@ -568,7 +567,6 @@ pub fn impl_py_setter_def(
|
||||||
_slf: *mut _pyo3::ffi::PyObject,
|
_slf: *mut _pyo3::ffi::PyObject,
|
||||||
_value: *mut _pyo3::ffi::PyObject,
|
_value: *mut _pyo3::ffi::PyObject,
|
||||||
) -> _pyo3::PyResult<::std::os::raw::c_int> {
|
) -> _pyo3::PyResult<::std::os::raw::c_int> {
|
||||||
#slf
|
|
||||||
let _value = _py
|
let _value = _py
|
||||||
.from_borrowed_ptr_or_opt(_value)
|
.from_borrowed_ptr_or_opt(_value)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
|
@ -597,8 +595,13 @@ pub fn impl_py_setter_def(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impl_call_getter(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<TokenStream> {
|
fn impl_call_getter(
|
||||||
|
cls: &syn::Type,
|
||||||
|
spec: &FnSpec<'_>,
|
||||||
|
self_type: &SelfType,
|
||||||
|
) -> syn::Result<TokenStream> {
|
||||||
let (py_arg, args) = split_off_python_arg(&spec.signature.arguments);
|
let (py_arg, args) = split_off_python_arg(&spec.signature.arguments);
|
||||||
|
let slf = self_type.receiver(cls, ExtractErrorMode::Raise);
|
||||||
ensure_spanned!(
|
ensure_spanned!(
|
||||||
args.is_empty(),
|
args.is_empty(),
|
||||||
args[0].ty.span() => "getter function can only have one argument (of type pyo3::Python)"
|
args[0].ty.span() => "getter function can only have one argument (of type pyo3::Python)"
|
||||||
|
@ -606,9 +609,9 @@ fn impl_call_getter(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<TokenStre
|
||||||
|
|
||||||
let name = &spec.name;
|
let name = &spec.name;
|
||||||
let fncall = if py_arg.is_some() {
|
let fncall = if py_arg.is_some() {
|
||||||
quote!(#cls::#name(_slf, _py))
|
quote!(#cls::#name(#slf, _py))
|
||||||
} else {
|
} else {
|
||||||
quote!(#cls::#name(_slf))
|
quote!(#cls::#name(#slf))
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(fncall)
|
Ok(fncall)
|
||||||
|
@ -621,33 +624,28 @@ pub fn impl_py_getter_def(
|
||||||
) -> Result<MethodAndMethodDef> {
|
) -> Result<MethodAndMethodDef> {
|
||||||
let python_name = property_type.null_terminated_python_name()?;
|
let python_name = property_type.null_terminated_python_name()?;
|
||||||
let doc = property_type.doc();
|
let doc = property_type.doc();
|
||||||
|
|
||||||
let getter_impl = match property_type {
|
let getter_impl = match property_type {
|
||||||
PropertyType::Descriptor {
|
PropertyType::Descriptor {
|
||||||
field: syn::Field {
|
field_index, field, ..
|
||||||
ident: Some(ident), ..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
// named struct field
|
let slf = SelfType::Receiver {
|
||||||
quote!(::std::clone::Clone::clone(&(_slf.#ident)))
|
mutable: false,
|
||||||
}
|
span: Span::call_site(),
|
||||||
PropertyType::Descriptor { field_index, .. } => {
|
}
|
||||||
// tuple struct field
|
.receiver(cls, ExtractErrorMode::Raise);
|
||||||
let index = syn::Index::from(field_index);
|
if let Some(ident) = &field.ident {
|
||||||
quote!(::std::clone::Clone::clone(&(_slf.#index)))
|
// named struct field
|
||||||
}
|
quote!(::std::clone::Clone::clone(&(#slf.#ident)))
|
||||||
PropertyType::Function { spec, .. } => impl_call_getter(cls, spec)?,
|
} else {
|
||||||
};
|
// tuple struct field
|
||||||
|
let index = syn::Index::from(field_index);
|
||||||
let slf = match property_type {
|
quote!(::std::clone::Clone::clone(&(#slf.#index)))
|
||||||
PropertyType::Descriptor { .. } => SelfType::Receiver {
|
}
|
||||||
mutable: false,
|
|
||||||
span: Span::call_site(),
|
|
||||||
}
|
|
||||||
.receiver(cls, ExtractErrorMode::Raise),
|
|
||||||
PropertyType::Function { self_type, .. } => {
|
|
||||||
self_type.receiver(cls, ExtractErrorMode::Raise)
|
|
||||||
}
|
}
|
||||||
|
PropertyType::Function {
|
||||||
|
spec, self_type, ..
|
||||||
|
} => impl_call_getter(cls, spec, self_type)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let conversion = match property_type {
|
let conversion = match property_type {
|
||||||
|
@ -699,7 +697,6 @@ pub fn impl_py_getter_def(
|
||||||
_py: _pyo3::Python<'_>,
|
_py: _pyo3::Python<'_>,
|
||||||
_slf: *mut _pyo3::ffi::PyObject
|
_slf: *mut _pyo3::ffi::PyObject
|
||||||
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
||||||
#slf
|
|
||||||
let item = #getter_impl;
|
let item = #getter_impl;
|
||||||
#conversion
|
#conversion
|
||||||
}
|
}
|
||||||
|
@ -1151,19 +1148,14 @@ fn generate_method_body(
|
||||||
extract_error_mode: ExtractErrorMode,
|
extract_error_mode: ExtractErrorMode,
|
||||||
return_mode: Option<&ReturnMode>,
|
return_mode: Option<&ReturnMode>,
|
||||||
) -> Result<TokenStream> {
|
) -> Result<TokenStream> {
|
||||||
let self_conversion = spec.tp.self_conversion(Some(cls), extract_error_mode);
|
let self_arg = spec.tp.self_arg(Some(cls), extract_error_mode);
|
||||||
let self_arg = spec.tp.self_arg();
|
|
||||||
let rust_name = spec.name;
|
let rust_name = spec.name;
|
||||||
let args = extract_proto_arguments(py, spec, arguments, extract_error_mode)?;
|
let args = extract_proto_arguments(py, spec, arguments, extract_error_mode)?;
|
||||||
let call = quote! { _pyo3::callback::convert(#py, #cls::#rust_name(#self_arg #(#args),*)) };
|
let call = quote! { _pyo3::callback::convert(#py, #cls::#rust_name(#self_arg #(#args),*)) };
|
||||||
let body = if let Some(return_mode) = return_mode {
|
Ok(if let Some(return_mode) = return_mode {
|
||||||
return_mode.return_call_output(py, call)
|
return_mode.return_call_output(py, call)
|
||||||
} else {
|
} else {
|
||||||
call
|
call
|
||||||
};
|
|
||||||
Ok(quote! {
|
|
||||||
#self_conversion
|
|
||||||
#body
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue