Merge pull request #2503 from davidhewitt/extract_argument_holder
pyfunction: use extract_argument with holder to avoid extractext
This commit is contained in:
commit
fa19f322d2
|
@ -73,6 +73,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Fix incorrect enum names being returned by `repr` for enums renamed by `#[pyclass(name)]` [#2457](https://github.com/PyO3/pyo3/pull/2457)
|
- Fix incorrect enum names being returned by `repr` for enums renamed by `#[pyclass(name)]` [#2457](https://github.com/PyO3/pyo3/pull/2457)
|
||||||
- Fix incorrect Python version cfg definition on `PyObject_CallNoArgs`[#2476](https://github.com/PyO3/pyo3/pull/2476)
|
- Fix incorrect Python version cfg definition on `PyObject_CallNoArgs`[#2476](https://github.com/PyO3/pyo3/pull/2476)
|
||||||
- Fix use-after-free in `PyCapsule` type. [#2481](https://github.com/PyO3/pyo3/pull/2481)
|
- Fix use-after-free in `PyCapsule` type. [#2481](https://github.com/PyO3/pyo3/pull/2481)
|
||||||
|
- Fix several clippy warnings generated by `#[pyfunction]` arguments. [#2503](https://github.com/PyO3/pyo3/pull/2503)
|
||||||
|
|
||||||
## [0.16.5] - 2022-05-15
|
## [0.16.5] - 2022-05-15
|
||||||
|
|
||||||
|
|
|
@ -967,12 +967,24 @@ impl ::pyo3::PyClass for MyClass {
|
||||||
type Frozen = pyo3::pyclass::boolean_struct::False;
|
type Frozen = pyo3::pyclass::boolean_struct::False;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ::pyo3::derive_utils::ExtractExt<'a> for &'a mut MyClass {
|
impl<'a, 'py> ::pyo3::impl_::extract_argument::PyFunctionArgument<'a, 'py> for &'a MyClass
|
||||||
type Target = ::pyo3::PyRefMut<'a, MyClass>;
|
{
|
||||||
|
type Holder = ::std::option::Option<::pyo3::PyRef<'py, MyClass>>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn extract(obj: &'py ::pyo3::PyAny, holder: &'a mut Self::Holder) -> ::pyo3::PyResult<Self> {
|
||||||
|
::pyo3::impl_::extract_argument::extract_pyclass_ref(obj, holder)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ::pyo3::derive_utils::ExtractExt<'a> for &'a MyClass {
|
impl<'a, 'py> ::pyo3::impl_::extract_argument::PyFunctionArgument<'a, 'py> for &'a mut MyClass
|
||||||
type Target = ::pyo3::PyRef<'a, MyClass>;
|
{
|
||||||
|
type Holder = ::std::option::Option<::pyo3::PyRefMut<'py, MyClass>>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn extract(obj: &'py ::pyo3::PyAny, holder: &'a mut Self::Holder) -> ::pyo3::PyResult<Self> {
|
||||||
|
::pyo3::impl_::extract_argument::extract_pyclass_ref_mut(obj, holder)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pyo3::IntoPy<PyObject> for MyClass {
|
impl pyo3::IntoPy<PyObject> for MyClass {
|
||||||
|
|
|
@ -148,6 +148,11 @@ pub fn print_feature_cfgs() {
|
||||||
if rustc_minor_version >= 51 {
|
if rustc_minor_version >= 51 {
|
||||||
println!("cargo:rustc-cfg=addr_of");
|
println!("cargo:rustc-cfg=addr_of");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enable use of Option::insert on Rust 1.53 and greater
|
||||||
|
if rustc_minor_version >= 53 {
|
||||||
|
println!("cargo:rustc-cfg=option_insert");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Private exports used in PyO3's build.rs
|
/// Private exports used in PyO3's build.rs
|
||||||
|
|
|
@ -460,9 +460,6 @@ impl<'a> FnSpec<'a> {
|
||||||
let deprecations = &self.deprecations;
|
let deprecations = &self.deprecations;
|
||||||
let self_conversion = self.tp.self_conversion(cls, ExtractErrorMode::Raise);
|
let self_conversion = self.tp.self_conversion(cls, ExtractErrorMode::Raise);
|
||||||
let self_arg = self.tp.self_arg();
|
let self_arg = self.tp.self_arg();
|
||||||
let arg_names = (0..self.args.len())
|
|
||||||
.map(|pos| syn::Ident::new(&format!("arg{}", pos), Span::call_site()))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
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;
|
||||||
let rust_name = if let Some(cls) = cls {
|
let rust_name = if let Some(cls) = cls {
|
||||||
|
@ -472,19 +469,22 @@ impl<'a> FnSpec<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// The method call is necessary to generate a decent error message.
|
// The method call is necessary to generate a decent error message.
|
||||||
let rust_call = quote! {
|
let rust_call = |args: Vec<TokenStream>| {
|
||||||
let mut ret = #rust_name(#self_arg #(#arg_names),*);
|
quote! {
|
||||||
|
let mut ret = #rust_name(#self_arg #(#args),*);
|
||||||
|
|
||||||
if false {
|
if false {
|
||||||
use _pyo3::impl_::ghost::IntoPyResult;
|
use _pyo3::impl_::ghost::IntoPyResult;
|
||||||
ret.assert_into_py_result();
|
ret.assert_into_py_result();
|
||||||
|
}
|
||||||
|
|
||||||
|
_pyo3::callback::convert(#py, ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
_pyo3::callback::convert(#py, ret)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(match self.convention {
|
Ok(match self.convention {
|
||||||
CallingConvention::Noargs => {
|
CallingConvention::Noargs => {
|
||||||
|
let call = rust_call(vec![]);
|
||||||
quote! {
|
quote! {
|
||||||
unsafe extern "C" fn #ident (
|
unsafe extern "C" fn #ident (
|
||||||
_slf: *mut _pyo3::ffi::PyObject,
|
_slf: *mut _pyo3::ffi::PyObject,
|
||||||
|
@ -496,13 +496,14 @@ impl<'a> FnSpec<'a> {
|
||||||
let #py = gil.python();
|
let #py = gil.python();
|
||||||
_pyo3::callback::panic_result_into_callback_output(#py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
_pyo3::callback::panic_result_into_callback_output(#py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
||||||
#self_conversion
|
#self_conversion
|
||||||
#rust_call
|
#call
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CallingConvention::Fastcall => {
|
CallingConvention::Fastcall => {
|
||||||
let arg_convert = impl_arg_params(self, cls, &py, true)?;
|
let (arg_convert, args) = impl_arg_params(self, cls, &py, true)?;
|
||||||
|
let call = rust_call(args);
|
||||||
quote! {
|
quote! {
|
||||||
unsafe extern "C" fn #ident (
|
unsafe extern "C" fn #ident (
|
||||||
_slf: *mut _pyo3::ffi::PyObject,
|
_slf: *mut _pyo3::ffi::PyObject,
|
||||||
|
@ -516,13 +517,14 @@ impl<'a> FnSpec<'a> {
|
||||||
_pyo3::callback::panic_result_into_callback_output(#py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
_pyo3::callback::panic_result_into_callback_output(#py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
||||||
#self_conversion
|
#self_conversion
|
||||||
#arg_convert
|
#arg_convert
|
||||||
#rust_call
|
#call
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CallingConvention::Varargs => {
|
CallingConvention::Varargs => {
|
||||||
let arg_convert = impl_arg_params(self, cls, &py, false)?;
|
let (arg_convert, args) = impl_arg_params(self, cls, &py, false)?;
|
||||||
|
let call = rust_call(args);
|
||||||
quote! {
|
quote! {
|
||||||
unsafe extern "C" fn #ident (
|
unsafe extern "C" fn #ident (
|
||||||
_slf: *mut _pyo3::ffi::PyObject,
|
_slf: *mut _pyo3::ffi::PyObject,
|
||||||
|
@ -535,14 +537,14 @@ impl<'a> FnSpec<'a> {
|
||||||
_pyo3::callback::panic_result_into_callback_output(#py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
_pyo3::callback::panic_result_into_callback_output(#py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
||||||
#self_conversion
|
#self_conversion
|
||||||
#arg_convert
|
#arg_convert
|
||||||
#rust_call
|
#call
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CallingConvention::TpNew => {
|
CallingConvention::TpNew => {
|
||||||
let rust_call = quote! { #rust_name(#(#arg_names),*) };
|
let (arg_convert, args) = impl_arg_params(self, cls, &py, false)?;
|
||||||
let arg_convert = impl_arg_params(self, cls, &py, false)?;
|
let call = quote! { #rust_name(#(#args),*) };
|
||||||
quote! {
|
quote! {
|
||||||
unsafe extern "C" fn #ident (
|
unsafe extern "C" fn #ident (
|
||||||
subtype: *mut _pyo3::ffi::PyTypeObject,
|
subtype: *mut _pyo3::ffi::PyTypeObject,
|
||||||
|
@ -555,7 +557,7 @@ impl<'a> FnSpec<'a> {
|
||||||
let #py = gil.python();
|
let #py = gil.python();
|
||||||
_pyo3::callback::panic_result_into_callback_output(#py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
_pyo3::callback::panic_result_into_callback_output(#py, ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
|
||||||
#arg_convert
|
#arg_convert
|
||||||
let result = #rust_call;
|
let result = #call;
|
||||||
let initializer: _pyo3::PyClassInitializer::<#cls> = result.convert(#py)?;
|
let initializer: _pyo3::PyClassInitializer::<#cls> = result.convert(#py)?;
|
||||||
initializer.into_new_object(#py, subtype)
|
initializer.into_new_object(#py, subtype)
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -4,7 +4,6 @@ use crate::{
|
||||||
attributes::FromPyWithAttribute,
|
attributes::FromPyWithAttribute,
|
||||||
method::{FnArg, FnSpec},
|
method::{FnArg, FnSpec},
|
||||||
pyfunction::Argument,
|
pyfunction::Argument,
|
||||||
utils::{remove_lifetime, unwrap_ty_group},
|
|
||||||
};
|
};
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::{quote, quote_spanned};
|
use quote::{quote, quote_spanned};
|
||||||
|
@ -55,9 +54,9 @@ pub fn impl_arg_params(
|
||||||
self_: Option<&syn::Type>,
|
self_: Option<&syn::Type>,
|
||||||
py: &syn::Ident,
|
py: &syn::Ident,
|
||||||
fastcall: bool,
|
fastcall: bool,
|
||||||
) -> Result<TokenStream> {
|
) -> Result<(TokenStream, Vec<TokenStream>)> {
|
||||||
if spec.args.is_empty() {
|
if spec.args.is_empty() {
|
||||||
return Ok(TokenStream::new());
|
return Ok((TokenStream::new(), vec![]));
|
||||||
}
|
}
|
||||||
|
|
||||||
let args_array = syn::Ident::new("output", Span::call_site());
|
let args_array = syn::Ident::new("output", Span::call_site());
|
||||||
|
@ -65,15 +64,18 @@ pub fn impl_arg_params(
|
||||||
if !fastcall && is_forwarded_args(&spec.args, &spec.attrs) {
|
if !fastcall && is_forwarded_args(&spec.args, &spec.attrs) {
|
||||||
// In the varargs convention, we can just pass though if the signature
|
// In the varargs convention, we can just pass though if the signature
|
||||||
// is (*args, **kwds).
|
// is (*args, **kwds).
|
||||||
let mut arg_convert = vec![];
|
let arg_convert = spec
|
||||||
for (i, arg) in spec.args.iter().enumerate() {
|
.args
|
||||||
arg_convert.push(impl_arg_param(arg, spec, i, &mut 0, py, &args_array)?);
|
.iter()
|
||||||
}
|
.map(|arg| impl_arg_param(arg, spec, &mut 0, py, &args_array))
|
||||||
return Ok(quote! {
|
.collect::<Result<_>>()?;
|
||||||
let _args = #py.from_borrowed_ptr::<_pyo3::types::PyTuple>(_args);
|
return Ok((
|
||||||
let _kwargs: ::std::option::Option<&_pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs);
|
quote! {
|
||||||
#(#arg_convert)*
|
let _args = #py.from_borrowed_ptr::<_pyo3::types::PyTuple>(_args);
|
||||||
});
|
let _kwargs: ::std::option::Option<&_pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs);
|
||||||
|
},
|
||||||
|
arg_convert,
|
||||||
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut positional_parameter_names = Vec::new();
|
let mut positional_parameter_names = Vec::new();
|
||||||
|
@ -111,18 +113,12 @@ pub fn impl_arg_params(
|
||||||
|
|
||||||
let num_params = positional_parameter_names.len() + keyword_only_parameters.len();
|
let num_params = positional_parameter_names.len() + keyword_only_parameters.len();
|
||||||
|
|
||||||
let mut param_conversion = Vec::new();
|
|
||||||
let mut option_pos = 0;
|
let mut option_pos = 0;
|
||||||
for (idx, arg) in spec.args.iter().enumerate() {
|
let param_conversion = spec
|
||||||
param_conversion.push(impl_arg_param(
|
.args
|
||||||
arg,
|
.iter()
|
||||||
spec,
|
.map(|arg| impl_arg_param(arg, spec, &mut option_pos, py, &args_array))
|
||||||
idx,
|
.collect::<Result<_>>()?;
|
||||||
&mut option_pos,
|
|
||||||
py,
|
|
||||||
&args_array,
|
|
||||||
)?);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (accept_args, accept_kwargs) = accept_args_kwargs(&spec.attrs);
|
let (accept_args, accept_kwargs) = accept_args_kwargs(&spec.attrs);
|
||||||
let args_handler = if accept_args {
|
let args_handler = if accept_args {
|
||||||
|
@ -165,21 +161,22 @@ pub fn impl_arg_params(
|
||||||
};
|
};
|
||||||
|
|
||||||
// create array of arguments, and then parse
|
// create array of arguments, and then parse
|
||||||
Ok(quote! {
|
Ok((
|
||||||
const DESCRIPTION: _pyo3::impl_::extract_argument::FunctionDescription = _pyo3::impl_::extract_argument::FunctionDescription {
|
quote! {
|
||||||
cls_name: #cls_name,
|
const DESCRIPTION: _pyo3::impl_::extract_argument::FunctionDescription = _pyo3::impl_::extract_argument::FunctionDescription {
|
||||||
func_name: stringify!(#python_name),
|
cls_name: #cls_name,
|
||||||
positional_parameter_names: &[#(#positional_parameter_names),*],
|
func_name: stringify!(#python_name),
|
||||||
positional_only_parameters: #positional_only_parameters,
|
positional_parameter_names: &[#(#positional_parameter_names),*],
|
||||||
required_positional_parameters: #required_positional_parameters,
|
positional_only_parameters: #positional_only_parameters,
|
||||||
keyword_only_parameters: &[#(#keyword_only_parameters),*],
|
required_positional_parameters: #required_positional_parameters,
|
||||||
};
|
keyword_only_parameters: &[#(#keyword_only_parameters),*],
|
||||||
|
};
|
||||||
|
|
||||||
let mut #args_array = [::std::option::Option::None; #num_params];
|
let mut #args_array = [::std::option::Option::None; #num_params];
|
||||||
let (_args, _kwargs) = #extract_expression;
|
let (_args, _kwargs) = #extract_expression;
|
||||||
|
},
|
||||||
#(#param_conversion)*
|
param_conversion,
|
||||||
})
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Re option_pos: The option slice doesn't contain the py: Python argument, so the argument
|
/// Re option_pos: The option slice doesn't contain the py: Python argument, so the argument
|
||||||
|
@ -187,7 +184,6 @@ pub fn impl_arg_params(
|
||||||
fn impl_arg_param(
|
fn impl_arg_param(
|
||||||
arg: &FnArg<'_>,
|
arg: &FnArg<'_>,
|
||||||
spec: &FnSpec<'_>,
|
spec: &FnSpec<'_>,
|
||||||
idx: usize,
|
|
||||||
option_pos: &mut usize,
|
option_pos: &mut usize,
|
||||||
py: &syn::Ident,
|
py: &syn::Ident,
|
||||||
args_array: &syn::Ident,
|
args_array: &syn::Ident,
|
||||||
|
@ -198,13 +194,10 @@ fn impl_arg_param(
|
||||||
($($tokens:tt)*) => { quote_spanned!(arg.ty.span() => $($tokens)*) }
|
($($tokens:tt)*) => { quote_spanned!(arg.ty.span() => $($tokens)*) }
|
||||||
}
|
}
|
||||||
|
|
||||||
let arg_name = syn::Ident::new(&format!("arg{}", idx), Span::call_site());
|
|
||||||
|
|
||||||
if arg.py {
|
if arg.py {
|
||||||
return Ok(quote_arg_span! { let #arg_name = #py; });
|
return Ok(quote_arg_span! { #py });
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty = arg.ty;
|
|
||||||
let name = arg.name;
|
let name = arg.name;
|
||||||
let name_str = name.to_string();
|
let name_str = name.to_string();
|
||||||
|
|
||||||
|
@ -214,7 +207,11 @@ fn impl_arg_param(
|
||||||
arg.name.span() => "args cannot be optional"
|
arg.name.span() => "args cannot be optional"
|
||||||
);
|
);
|
||||||
return Ok(quote_arg_span! {
|
return Ok(quote_arg_span! {
|
||||||
let #arg_name = _pyo3::impl_::extract_argument::extract_argument(_args, #name_str)?;
|
_pyo3::impl_::extract_argument::extract_argument(
|
||||||
|
_args,
|
||||||
|
&mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT },
|
||||||
|
#name_str
|
||||||
|
)?
|
||||||
});
|
});
|
||||||
} else if is_kwargs(&spec.attrs, name) {
|
} else if is_kwargs(&spec.attrs, name) {
|
||||||
ensure_spanned!(
|
ensure_spanned!(
|
||||||
|
@ -222,31 +219,35 @@ fn impl_arg_param(
|
||||||
arg.name.span() => "kwargs must be Option<_>"
|
arg.name.span() => "kwargs must be Option<_>"
|
||||||
);
|
);
|
||||||
return Ok(quote_arg_span! {
|
return Ok(quote_arg_span! {
|
||||||
let #arg_name = _pyo3::impl_::extract_argument::extract_optional_argument(_kwargs.map(|kwargs| kwargs.as_ref()), #name_str)?;
|
_pyo3::impl_::extract_argument::extract_optional_argument(
|
||||||
|
_kwargs.map(|kwargs| kwargs.as_ref()),
|
||||||
|
&mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT },
|
||||||
|
#name_str
|
||||||
|
)?
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let arg_value = quote_arg_span!(#args_array[#option_pos]);
|
let arg_value = quote_arg_span!(#args_array[#option_pos]);
|
||||||
*option_pos += 1;
|
*option_pos += 1;
|
||||||
|
|
||||||
let arg_value_or_default = if let Some(FromPyWithAttribute {
|
let tokens = if let Some(FromPyWithAttribute {
|
||||||
value: expr_path, ..
|
value: expr_path, ..
|
||||||
}) = &arg.attrs.from_py_with
|
}) = &arg.attrs.from_py_with
|
||||||
{
|
{
|
||||||
match (spec.default_value(name), arg.optional.is_some()) {
|
match (spec.default_value(name), arg.optional.is_some()) {
|
||||||
(Some(default), true) if default.to_string() != "None" => {
|
(Some(default), true) if default.to_string() != "None" => {
|
||||||
quote_arg_span! {
|
quote_arg_span! {
|
||||||
_pyo3::impl_::extract_argument::from_py_with_with_default(#arg_value, #name_str, #expr_path, || Some(#default))
|
_pyo3::impl_::extract_argument::from_py_with_with_default(#arg_value, #name_str, #expr_path, || Some(#default))?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Some(default), _) => {
|
(Some(default), _) => {
|
||||||
quote_arg_span! {
|
quote_arg_span! {
|
||||||
_pyo3::impl_::extract_argument::from_py_with_with_default(#arg_value, #name_str, #expr_path, || #default)
|
_pyo3::impl_::extract_argument::from_py_with_with_default(#arg_value, #name_str, #expr_path, || #default)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(None, true) => {
|
(None, true) => {
|
||||||
quote_arg_span! {
|
quote_arg_span! {
|
||||||
_pyo3::impl_::extract_argument::from_py_with_with_default(#arg_value, #name_str, #expr_path, || Some(None))
|
_pyo3::impl_::extract_argument::from_py_with_with_default(#arg_value, #name_str, #expr_path, || Some(None))?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(None, false) => {
|
(None, false) => {
|
||||||
|
@ -255,7 +256,7 @@ fn impl_arg_param(
|
||||||
_pyo3::impl_::extract_argument::unwrap_required_argument(#arg_value),
|
_pyo3::impl_::extract_argument::unwrap_required_argument(#arg_value),
|
||||||
#name_str,
|
#name_str,
|
||||||
#expr_path,
|
#expr_path,
|
||||||
)
|
)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,59 +264,43 @@ fn impl_arg_param(
|
||||||
match (spec.default_value(name), arg.optional.is_some()) {
|
match (spec.default_value(name), arg.optional.is_some()) {
|
||||||
(Some(default), true) if default.to_string() != "None" => {
|
(Some(default), true) if default.to_string() != "None" => {
|
||||||
quote_arg_span! {
|
quote_arg_span! {
|
||||||
_pyo3::impl_::extract_argument::extract_argument_with_default(#arg_value, #name_str, || Some(#default))
|
_pyo3::impl_::extract_argument::extract_argument_with_default(
|
||||||
|
#arg_value,
|
||||||
|
&mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT },
|
||||||
|
#name_str,
|
||||||
|
|| Some(#default)
|
||||||
|
)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Some(default), _) => {
|
(Some(default), _) => {
|
||||||
quote_arg_span! {
|
quote_arg_span! {
|
||||||
_pyo3::impl_::extract_argument::extract_argument_with_default(#arg_value, #name_str, || #default)
|
_pyo3::impl_::extract_argument::extract_argument_with_default(
|
||||||
|
#arg_value,
|
||||||
|
&mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT },
|
||||||
|
#name_str,
|
||||||
|
|| #default
|
||||||
|
)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(None, true) => {
|
(None, true) => {
|
||||||
quote_arg_span! {
|
quote_arg_span! {
|
||||||
_pyo3::impl_::extract_argument::extract_optional_argument(#arg_value, #name_str)
|
_pyo3::impl_::extract_argument::extract_optional_argument(
|
||||||
|
#arg_value,
|
||||||
|
&mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT },
|
||||||
|
#name_str
|
||||||
|
)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(None, false) => {
|
(None, false) => {
|
||||||
quote_arg_span! {
|
quote_arg_span! {
|
||||||
_pyo3::impl_::extract_argument::extract_argument(
|
_pyo3::impl_::extract_argument::extract_argument(
|
||||||
_pyo3::impl_::extract_argument::unwrap_required_argument(#arg_value),
|
_pyo3::impl_::extract_argument::unwrap_required_argument(#arg_value),
|
||||||
|
&mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT },
|
||||||
#name_str
|
#name_str
|
||||||
)
|
)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Ok(tokens)
|
||||||
return if let syn::Type::Reference(tref) = unwrap_ty_group(arg.optional.unwrap_or(ty)) {
|
|
||||||
let tref = remove_lifetime(tref);
|
|
||||||
let mut_ = tref.mutability;
|
|
||||||
let (target_ty, borrow_tmp) = if arg.optional.is_some() {
|
|
||||||
// Get Option<&T> from Option<PyRef<T>>
|
|
||||||
(
|
|
||||||
quote_arg_span! { ::std::option::Option<<#tref as _pyo3::derive_utils::ExtractExt<'_>>::Target> },
|
|
||||||
if mut_.is_some() {
|
|
||||||
quote_arg_span! { _tmp.as_deref_mut() }
|
|
||||||
} else {
|
|
||||||
quote_arg_span! { _tmp.as_deref() }
|
|
||||||
},
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
// Get &T from PyRef<T>
|
|
||||||
(
|
|
||||||
quote_arg_span! { <#tref as _pyo3::derive_utils::ExtractExt<'_>>::Target },
|
|
||||||
quote_arg_span! { &#mut_ *_tmp },
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(quote_arg_span! {
|
|
||||||
let #mut_ _tmp: #target_ty = #arg_value_or_default?;
|
|
||||||
#[allow(clippy::needless_option_as_deref)]
|
|
||||||
let #arg_name = #borrow_tmp;
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Ok(quote_arg_span! {
|
|
||||||
let #arg_name = #arg_value_or_default?;
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -777,21 +777,36 @@ impl<'a> PyClassImplsBuilder<'a> {
|
||||||
let cls = self.cls;
|
let cls = self.cls;
|
||||||
if self.attr.options.frozen.is_some() {
|
if self.attr.options.frozen.is_some() {
|
||||||
quote! {
|
quote! {
|
||||||
impl<'a> _pyo3::derive_utils::ExtractExt<'a> for &'a #cls
|
impl<'a, 'py> _pyo3::impl_::extract_argument::PyFunctionArgument<'a, 'py> for &'a #cls
|
||||||
{
|
{
|
||||||
type Target = _pyo3::PyRef<'a, #cls>;
|
type Holder = ::std::option::Option<_pyo3::PyRef<'py, #cls>>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn extract(obj: &'py _pyo3::PyAny, holder: &'a mut Self::Holder) -> _pyo3::PyResult<Self> {
|
||||||
|
_pyo3::impl_::extract_argument::extract_pyclass_ref(obj, holder)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
impl<'a> _pyo3::derive_utils::ExtractExt<'a> for &'a #cls
|
impl<'a, 'py> _pyo3::impl_::extract_argument::PyFunctionArgument<'a, 'py> for &'a #cls
|
||||||
{
|
{
|
||||||
type Target = _pyo3::PyRef<'a, #cls>;
|
type Holder = ::std::option::Option<_pyo3::PyRef<'py, #cls>>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn extract(obj: &'py _pyo3::PyAny, holder: &'a mut Self::Holder) -> _pyo3::PyResult<Self> {
|
||||||
|
_pyo3::impl_::extract_argument::extract_pyclass_ref(obj, holder)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> _pyo3::derive_utils::ExtractExt<'a> for &'a mut #cls
|
impl<'a, 'py> _pyo3::impl_::extract_argument::PyFunctionArgument<'a, 'py> for &'a mut #cls
|
||||||
{
|
{
|
||||||
type Target = _pyo3::PyRefMut<'a, #cls>;
|
type Holder = ::std::option::Option<_pyo3::PyRefMut<'py, #cls>>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn extract(obj: &'py _pyo3::PyAny, holder: &'a mut Self::Holder) -> _pyo3::PyResult<Self> {
|
||||||
|
_pyo3::impl_::extract_argument::extract_pyclass_ref_mut(obj, holder)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::attributes::NameAttribute;
|
use crate::attributes::NameAttribute;
|
||||||
use crate::method::{CallingConvention, ExtractErrorMode};
|
use crate::method::{CallingConvention, ExtractErrorMode};
|
||||||
use crate::utils::{ensure_not_async_fn, remove_lifetime, unwrap_ty_group, PythonDoc};
|
use crate::utils::{ensure_not_async_fn, PythonDoc};
|
||||||
use crate::{deprecations::Deprecations, utils};
|
use crate::{deprecations::Deprecations, utils};
|
||||||
use crate::{
|
use crate::{
|
||||||
method::{FnArg, FnSpec, FnType, SelfType},
|
method::{FnArg, FnSpec, FnType, SelfType},
|
||||||
|
@ -12,7 +12,6 @@ use crate::{
|
||||||
};
|
};
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::{format_ident, quote, ToTokens};
|
use quote::{format_ident, quote, ToTokens};
|
||||||
use syn::Ident;
|
|
||||||
use syn::{ext::IdentExt, spanned::Spanned, Result};
|
use syn::{ext::IdentExt, spanned::Spanned, Result};
|
||||||
|
|
||||||
/// Generated code for a single pymethod item.
|
/// Generated code for a single pymethod item.
|
||||||
|
@ -839,81 +838,66 @@ impl Ty {
|
||||||
arg: &FnArg<'_>,
|
arg: &FnArg<'_>,
|
||||||
extract_error_mode: ExtractErrorMode,
|
extract_error_mode: ExtractErrorMode,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
|
let name_str = arg.name.unraw().to_string();
|
||||||
match self {
|
match self {
|
||||||
Ty::Object => {
|
Ty::Object => extract_object(
|
||||||
let extract = handle_error(
|
extract_error_mode,
|
||||||
extract_error_mode,
|
py,
|
||||||
py,
|
&name_str,
|
||||||
quote! {
|
|
||||||
#py.from_borrowed_ptr::<_pyo3::PyAny>(#ident).extract()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
extract_object(arg.ty, ident, extract)
|
|
||||||
}
|
|
||||||
Ty::MaybeNullObject => {
|
|
||||||
let extract = handle_error(
|
|
||||||
extract_error_mode,
|
|
||||||
py,
|
|
||||||
quote! {
|
|
||||||
#py.from_borrowed_ptr::<_pyo3::PyAny>(
|
|
||||||
if #ident.is_null() {
|
|
||||||
_pyo3::ffi::Py_None()
|
|
||||||
} else {
|
|
||||||
#ident
|
|
||||||
}
|
|
||||||
).extract()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
extract_object(arg.ty, ident, extract)
|
|
||||||
}
|
|
||||||
Ty::NonNullObject => {
|
|
||||||
let extract = handle_error(
|
|
||||||
extract_error_mode,
|
|
||||||
py,
|
|
||||||
quote! {
|
|
||||||
#py.from_borrowed_ptr::<_pyo3::PyAny>(#ident.as_ptr()).extract()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
extract_object(arg.ty, ident, extract)
|
|
||||||
}
|
|
||||||
Ty::IPowModulo => {
|
|
||||||
let extract = handle_error(
|
|
||||||
extract_error_mode,
|
|
||||||
py,
|
|
||||||
quote! {
|
|
||||||
#ident.extract(#py)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
extract_object(arg.ty, ident, extract)
|
|
||||||
}
|
|
||||||
Ty::CompareOp => {
|
|
||||||
let extract = handle_error(
|
|
||||||
extract_error_mode,
|
|
||||||
py,
|
|
||||||
quote! {
|
|
||||||
_pyo3::class::basic::CompareOp::from_raw(#ident)
|
|
||||||
.ok_or_else(|| _pyo3::exceptions::PyValueError::new_err("invalid comparison operator"))
|
|
||||||
},
|
|
||||||
);
|
|
||||||
quote! {
|
quote! {
|
||||||
let #ident = #extract;
|
#py.from_borrowed_ptr::<_pyo3::PyAny>(#ident)
|
||||||
}
|
},
|
||||||
}
|
),
|
||||||
|
Ty::MaybeNullObject => extract_object(
|
||||||
|
extract_error_mode,
|
||||||
|
py,
|
||||||
|
&name_str,
|
||||||
|
quote! {
|
||||||
|
#py.from_borrowed_ptr::<_pyo3::PyAny>(
|
||||||
|
if #ident.is_null() {
|
||||||
|
_pyo3::ffi::Py_None()
|
||||||
|
} else {
|
||||||
|
#ident
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Ty::NonNullObject => extract_object(
|
||||||
|
extract_error_mode,
|
||||||
|
py,
|
||||||
|
&name_str,
|
||||||
|
quote! {
|
||||||
|
#py.from_borrowed_ptr::<_pyo3::PyAny>(#ident.as_ptr())
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Ty::IPowModulo => extract_object(
|
||||||
|
extract_error_mode,
|
||||||
|
py,
|
||||||
|
&name_str,
|
||||||
|
quote! {
|
||||||
|
#ident.to_borrowed_any(#py)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Ty::CompareOp => handle_error(
|
||||||
|
extract_error_mode,
|
||||||
|
py,
|
||||||
|
quote! {
|
||||||
|
_pyo3::class::basic::CompareOp::from_raw(#ident)
|
||||||
|
.ok_or_else(|| _pyo3::exceptions::PyValueError::new_err("invalid comparison operator"))
|
||||||
|
},
|
||||||
|
),
|
||||||
Ty::PySsizeT => {
|
Ty::PySsizeT => {
|
||||||
let ty = arg.ty;
|
let ty = arg.ty;
|
||||||
let extract = handle_error(
|
handle_error(
|
||||||
extract_error_mode,
|
extract_error_mode,
|
||||||
py,
|
py,
|
||||||
quote! {
|
quote! {
|
||||||
::std::convert::TryInto::<#ty>::try_into(#ident).map_err(|e| _pyo3::exceptions::PyValueError::new_err(e.to_string()))
|
::std::convert::TryInto::<#ty>::try_into(#ident).map_err(|e| _pyo3::exceptions::PyValueError::new_err(e.to_string()))
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
quote! {
|
|
||||||
let #ident = #extract;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Just pass other types through unmodified
|
// Just pass other types through unmodified
|
||||||
Ty::PyBuffer | Ty::Int | Ty::PyHashT | Ty::Void => quote! {},
|
Ty::PyBuffer | Ty::Int | Ty::PyHashT | Ty::Void => quote! { #ident },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -934,19 +918,23 @@ fn handle_error(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_object(target: &syn::Type, ident: &syn::Ident, extract: TokenStream) -> TokenStream {
|
fn extract_object(
|
||||||
if let syn::Type::Reference(tref) = unwrap_ty_group(target) {
|
extract_error_mode: ExtractErrorMode,
|
||||||
let tref = remove_lifetime(tref);
|
py: &syn::Ident,
|
||||||
let mut_ = tref.mutability;
|
name: &str,
|
||||||
|
source: TokenStream,
|
||||||
|
) -> TokenStream {
|
||||||
|
handle_error(
|
||||||
|
extract_error_mode,
|
||||||
|
py,
|
||||||
quote! {
|
quote! {
|
||||||
let #mut_ #ident: <#tref as _pyo3::derive_utils::ExtractExt<'_>>::Target = #extract;
|
_pyo3::impl_::extract_argument::extract_argument(
|
||||||
let #ident = &#mut_ *#ident;
|
#source,
|
||||||
}
|
&mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT },
|
||||||
} else {
|
#name
|
||||||
quote! {
|
)
|
||||||
let #ident = #extract;
|
},
|
||||||
}
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ReturnMode {
|
enum ReturnMode {
|
||||||
|
@ -1096,12 +1084,8 @@ fn generate_method_body(
|
||||||
) -> Result<TokenStream> {
|
) -> Result<TokenStream> {
|
||||||
let self_conversion = spec.tp.self_conversion(Some(cls), extract_error_mode);
|
let self_conversion = spec.tp.self_conversion(Some(cls), extract_error_mode);
|
||||||
let rust_name = spec.name;
|
let rust_name = spec.name;
|
||||||
let (arg_idents, arg_count, conversions) =
|
let args = extract_proto_arguments(py, spec, arguments, extract_error_mode)?;
|
||||||
extract_proto_arguments(py, &spec.args, arguments, extract_error_mode)?;
|
let call = quote! { _pyo3::callback::convert(#py, #cls::#rust_name(_slf, #(#args),*)) };
|
||||||
if arg_count != arguments.len() {
|
|
||||||
bail_spanned!(spec.name.span() => format!("Expected {} arguments, got {}", arguments.len(), arg_count));
|
|
||||||
}
|
|
||||||
let call = quote! { _pyo3::callback::convert(#py, #cls::#rust_name(_slf, #(#arg_idents),*)) };
|
|
||||||
let body = if let Some(return_mode) = return_mode {
|
let body = if let Some(return_mode) = return_mode {
|
||||||
return_mode.return_call_output(py, call)
|
return_mode.return_call_output(py, call)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1109,7 +1093,6 @@ fn generate_method_body(
|
||||||
};
|
};
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#self_conversion
|
#self_conversion
|
||||||
#conversions
|
|
||||||
#body
|
#body
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1243,30 +1226,30 @@ const __RPOW__: SlotFragmentDef = SlotFragmentDef::new("__rpow__", &[Ty::Object,
|
||||||
|
|
||||||
fn extract_proto_arguments(
|
fn extract_proto_arguments(
|
||||||
py: &syn::Ident,
|
py: &syn::Ident,
|
||||||
method_args: &[FnArg<'_>],
|
spec: &FnSpec<'_>,
|
||||||
proto_args: &[Ty],
|
proto_args: &[Ty],
|
||||||
extract_error_mode: ExtractErrorMode,
|
extract_error_mode: ExtractErrorMode,
|
||||||
) -> Result<(Vec<Ident>, usize, TokenStream)> {
|
) -> Result<Vec<TokenStream>> {
|
||||||
let mut arg_idents = Vec::with_capacity(method_args.len());
|
let mut args = Vec::with_capacity(spec.args.len());
|
||||||
let mut non_python_args = 0;
|
let mut non_python_args = 0;
|
||||||
|
|
||||||
let mut args_conversions = Vec::with_capacity(proto_args.len());
|
for arg in &spec.args {
|
||||||
|
|
||||||
for arg in method_args {
|
|
||||||
if arg.py {
|
if arg.py {
|
||||||
arg_idents.push(py.clone());
|
args.push(quote! { #py });
|
||||||
} else {
|
} else {
|
||||||
let ident = syn::Ident::new(&format!("arg{}", non_python_args), Span::call_site());
|
let ident = syn::Ident::new(&format!("arg{}", non_python_args), Span::call_site());
|
||||||
let conversions = proto_args.get(non_python_args)
|
let conversions = proto_args.get(non_python_args)
|
||||||
.ok_or_else(|| err_spanned!(arg.ty.span() => format!("Expected at most {} non-python arguments", proto_args.len())))?
|
.ok_or_else(|| err_spanned!(arg.ty.span() => format!("Expected at most {} non-python arguments", proto_args.len())))?
|
||||||
.extract(py, &ident, arg, extract_error_mode);
|
.extract(py, &ident, arg, extract_error_mode);
|
||||||
non_python_args += 1;
|
non_python_args += 1;
|
||||||
args_conversions.push(conversions);
|
args.push(conversions);
|
||||||
arg_idents.push(ident);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let conversions = quote!(#(#args_conversions)*);
|
|
||||||
Ok((arg_idents, non_python_args, conversions))
|
if non_python_args != proto_args.len() {
|
||||||
|
bail_spanned!(spec.name.span() => format!("Expected {} arguments, got {}", proto_args.len(), non_python_args));
|
||||||
|
}
|
||||||
|
Ok(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StaticIdent(&'static str);
|
struct StaticIdent(&'static str);
|
||||||
|
|
|
@ -164,13 +164,6 @@ pub fn unwrap_ty_group(mut ty: &syn::Type) -> &syn::Type {
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove lifetime from reference
|
|
||||||
pub(crate) fn remove_lifetime(tref: &syn::TypeReference) -> syn::TypeReference {
|
|
||||||
let mut tref = tref.to_owned();
|
|
||||||
tref.lifetime = None;
|
|
||||||
tref
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extract the path to the pyo3 crate, or use the default (`::pyo3`).
|
/// Extract the path to the pyo3 crate, or use the default (`::pyo3`).
|
||||||
pub(crate) fn get_pyo3_crate(attr: &Option<CrateAttribute>) -> syn::Path {
|
pub(crate) fn get_pyo3_crate(attr: &Option<CrateAttribute>) -> syn::Path {
|
||||||
attr.as_ref()
|
attr.as_ref()
|
||||||
|
|
|
@ -733,7 +733,7 @@ where
|
||||||
.try_borrow_mut()?
|
.try_borrow_mut()?
|
||||||
.__ipow__(
|
.__ipow__(
|
||||||
extract_or_return_not_implemented!(other),
|
extract_or_return_not_implemented!(other),
|
||||||
match modulo.extract(py) {
|
match modulo.to_borrowed_any(py).extract() {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let res = crate::ffi::Py_NotImplemented();
|
let res = crate::ffi::Py_NotImplemented();
|
||||||
|
|
|
@ -6,19 +6,6 @@
|
||||||
|
|
||||||
use crate::{types::PyModule, PyCell, PyClass, PyErr, Python};
|
use crate::{types::PyModule, PyCell, PyClass, PyErr, Python};
|
||||||
|
|
||||||
/// Utility trait to enable &PyClass as a pymethod/function argument
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub trait ExtractExt<'a> {
|
|
||||||
type Target: crate::FromPyObject<'a>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> ExtractExt<'a> for T
|
|
||||||
where
|
|
||||||
T: crate::FromPyObject<'a>,
|
|
||||||
{
|
|
||||||
type Target = T;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait for types that can be borrowed from a cell.
|
/// A trait for types that can be borrowed from a cell.
|
||||||
///
|
///
|
||||||
/// This serves to unify the use of `PyRef` and `PyRefMut` in automatically
|
/// This serves to unify the use of `PyRef` and `PyRefMut` in automatically
|
||||||
|
|
|
@ -1,17 +1,91 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
exceptions::PyTypeError,
|
exceptions::PyTypeError,
|
||||||
ffi,
|
ffi,
|
||||||
|
pyclass::boolean_struct::False,
|
||||||
types::{PyDict, PyString, PyTuple},
|
types::{PyDict, PyString, PyTuple},
|
||||||
FromPyObject, PyAny, PyErr, PyResult, PyTypeInfo, Python,
|
FromPyObject, PyAny, PyClass, PyErr, PyRef, PyRefMut, PyResult, PyTypeInfo, Python,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A trait which is used to help PyO3 macros extract function arguments.
|
||||||
|
///
|
||||||
|
/// `#[pyclass]` structs need to extract as `PyRef<T>` and `PyRefMut<T>`
|
||||||
|
/// wrappers rather than extracting `&T` and `&mut T` directly. The `Holder` type is used
|
||||||
|
/// to hold these temporary wrappers - the way the macro is constructed, these wrappers
|
||||||
|
/// will be dropped as soon as the pyfunction call ends.
|
||||||
|
///
|
||||||
|
/// There exists a trivial blanket implementation for `T: FromPyObject` with `Holder = ()`.
|
||||||
|
pub trait PyFunctionArgument<'a, 'py>: Sized + 'a {
|
||||||
|
type Holder: FunctionArgumentHolder;
|
||||||
|
fn extract(obj: &'py PyAny, holder: &'a mut Self::Holder) -> PyResult<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'py, T> PyFunctionArgument<'a, 'py> for T
|
||||||
|
where
|
||||||
|
T: FromPyObject<'py> + 'a,
|
||||||
|
{
|
||||||
|
type Holder = ();
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn extract(obj: &'py PyAny, _: &'a mut ()) -> PyResult<Self> {
|
||||||
|
obj.extract()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for types which can be a function argument holder - they should
|
||||||
|
/// to be able to const-initialize to an empty value.
|
||||||
|
pub trait FunctionArgumentHolder: Sized {
|
||||||
|
const INIT: Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionArgumentHolder for () {
|
||||||
|
const INIT: Self = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> FunctionArgumentHolder for Option<T> {
|
||||||
|
const INIT: Self = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn extract_pyclass_ref<'a, 'py: 'a, T: PyClass>(
|
||||||
|
obj: &'py PyAny,
|
||||||
|
holder: &'a mut Option<PyRef<'py, T>>,
|
||||||
|
) -> PyResult<&'a T> {
|
||||||
|
#[cfg(not(option_insert))]
|
||||||
|
{
|
||||||
|
*holder = Some(obj.extract()?);
|
||||||
|
return Ok(holder.as_deref().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(option_insert)]
|
||||||
|
Ok(&*holder.insert(obj.extract()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn extract_pyclass_ref_mut<'a, 'py: 'a, T: PyClass<Frozen = False>>(
|
||||||
|
obj: &'py PyAny,
|
||||||
|
holder: &'a mut Option<PyRefMut<'py, T>>,
|
||||||
|
) -> PyResult<&'a mut T> {
|
||||||
|
#[cfg(not(option_insert))]
|
||||||
|
{
|
||||||
|
*holder = Some(obj.extract()?);
|
||||||
|
return Ok(holder.as_deref_mut().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(option_insert)]
|
||||||
|
Ok(&mut *holder.insert(obj.extract()?))
|
||||||
|
}
|
||||||
|
|
||||||
/// The standard implementation of how PyO3 extracts a `#[pyfunction]` or `#[pymethod]` function argument.
|
/// The standard implementation of how PyO3 extracts a `#[pyfunction]` or `#[pymethod]` function argument.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn extract_argument<'py, T>(obj: &'py PyAny, arg_name: &str) -> PyResult<T>
|
pub fn extract_argument<'a, 'py, T>(
|
||||||
|
obj: &'py PyAny,
|
||||||
|
holder: &'a mut T::Holder,
|
||||||
|
arg_name: &str,
|
||||||
|
) -> PyResult<T>
|
||||||
where
|
where
|
||||||
T: FromPyObject<'py>,
|
T: PyFunctionArgument<'a, 'py>,
|
||||||
{
|
{
|
||||||
match obj.extract() {
|
match PyFunctionArgument::extract(obj, holder) {
|
||||||
Ok(value) => Ok(value),
|
Ok(value) => Ok(value),
|
||||||
Err(e) => Err(argument_extraction_error(obj.py(), arg_name, e)),
|
Err(e) => Err(argument_extraction_error(obj.py(), arg_name, e)),
|
||||||
}
|
}
|
||||||
|
@ -20,31 +94,39 @@ where
|
||||||
/// Alternative to [`extract_argument`] used for `Option<T>` arguments (because they are implicitly treated
|
/// Alternative to [`extract_argument`] used for `Option<T>` arguments (because they are implicitly treated
|
||||||
/// as optional if at the end of the positional parameters).
|
/// as optional if at the end of the positional parameters).
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn extract_optional_argument<'py, T>(
|
pub fn extract_optional_argument<'a, 'py, T>(
|
||||||
obj: Option<&'py PyAny>,
|
obj: Option<&'py PyAny>,
|
||||||
|
holder: &'a mut T::Holder,
|
||||||
arg_name: &str,
|
arg_name: &str,
|
||||||
) -> PyResult<Option<T>>
|
) -> PyResult<Option<T>>
|
||||||
where
|
where
|
||||||
T: FromPyObject<'py>,
|
T: PyFunctionArgument<'a, 'py>,
|
||||||
{
|
{
|
||||||
match obj {
|
match obj {
|
||||||
Some(obj) => extract_argument(obj, arg_name),
|
Some(obj) => {
|
||||||
|
if obj.is_none() {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
extract_argument(obj, holder, arg_name).map(Some)
|
||||||
|
}
|
||||||
|
}
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alternative to [`extract_argument`] used when the argument has a default value provided by an annotation.
|
/// Alternative to [`extract_argument`] used when the argument has a default value provided by an annotation.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn extract_argument_with_default<'py, T>(
|
pub fn extract_argument_with_default<'a, 'py, T>(
|
||||||
obj: Option<&'py PyAny>,
|
obj: Option<&'py PyAny>,
|
||||||
|
holder: &'a mut T::Holder,
|
||||||
arg_name: &str,
|
arg_name: &str,
|
||||||
default: fn() -> T,
|
default: fn() -> T,
|
||||||
) -> PyResult<T>
|
) -> PyResult<T>
|
||||||
where
|
where
|
||||||
T: FromPyObject<'py>,
|
T: PyFunctionArgument<'a, 'py>,
|
||||||
{
|
{
|
||||||
match obj {
|
match obj {
|
||||||
Some(obj) => extract_argument(obj, arg_name),
|
Some(obj) => extract_argument(obj, holder, arg_name),
|
||||||
None => Ok(default()),
|
None => Ok(default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::internal_tricks::{extract_cstr_or_leak_cstring, NulByteInString};
|
use crate::internal_tricks::{extract_cstr_or_leak_cstring, NulByteInString};
|
||||||
use crate::{ffi, AsPyPointer, FromPyObject, PyAny, PyObject, PyResult, Python};
|
use crate::{ffi, AsPyPointer, PyAny, PyObject, PyResult, Python};
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::os::raw::{c_int, c_void};
|
use std::os::raw::{c_int, c_void};
|
||||||
|
@ -25,14 +25,14 @@ pub type ipowfunc = unsafe extern "C" fn(
|
||||||
impl IPowModulo {
|
impl IPowModulo {
|
||||||
#[cfg(Py_3_8)]
|
#[cfg(Py_3_8)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extract<'a, T: FromPyObject<'a>>(self, py: Python<'a>) -> PyResult<T> {
|
pub fn to_borrowed_any(self, py: Python<'_>) -> &PyAny {
|
||||||
unsafe { py.from_borrowed_ptr::<PyAny>(self.0) }.extract()
|
unsafe { py.from_borrowed_ptr::<PyAny>(self.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(Py_3_8))]
|
#[cfg(not(Py_3_8))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extract<'a, T: FromPyObject<'a>>(self, py: Python<'a>) -> PyResult<T> {
|
pub fn to_borrowed_any(self, py: Python<'_>) -> &PyAny {
|
||||||
unsafe { py.from_borrowed_ptr::<PyAny>(ffi::Py_None()) }.extract()
|
unsafe { py.from_borrowed_ptr::<PyAny>(ffi::Py_None()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue