pyo3/pyo3-derive-backend/src/py_method.rs

744 lines
24 KiB
Rust
Raw Normal View History

2017-05-16 05:24:06 +00:00
// Copyright (c) 2017-present PyO3 Project and Contributors
2017-05-20 06:14:59 +00:00
use method::{FnArg, FnSpec, FnType};
2018-07-03 20:28:40 +00:00
use quote::ToTokens;
use syn;
2017-05-18 07:05:49 +00:00
2018-07-03 20:28:40 +00:00
use proc_macro2::{Span, TokenStream};
2017-06-13 04:08:59 +00:00
use utils;
2017-05-16 05:24:06 +00:00
pub fn gen_py_method<'a>(
cls: &syn::Type,
name: &syn::Ident,
sig: &mut syn::MethodSig,
2018-07-03 20:28:40 +00:00
meth_attrs: &mut Vec<syn::Attribute>,
) -> TokenStream {
2017-05-16 05:24:06 +00:00
check_generic(name, sig);
2017-06-18 15:00:27 +00:00
let doc = utils::get_doc(&meth_attrs, true);
2017-05-20 06:14:59 +00:00
let spec = FnSpec::parse(name, sig, meth_attrs);
2017-05-16 05:24:06 +00:00
2017-05-20 06:14:59 +00:00
match spec.tp {
2018-07-03 20:28:40 +00:00
FnType::Fn => impl_py_method_def(name, doc, &spec, &impl_wrap(cls, name, &spec, true)),
FnType::FnNew => impl_py_method_def_new(name, doc, &impl_wrap_new(cls, name, &spec)),
FnType::FnInit => impl_py_method_def_init(name, doc, &impl_wrap_init(cls, name, &spec)),
FnType::FnCall => impl_py_method_def_call(name, doc, &impl_wrap(cls, name, &spec, false)),
FnType::FnClass => impl_py_method_def_class(name, doc, &impl_wrap_class(cls, name, &spec)),
FnType::FnStatic => {
impl_py_method_def_static(name, doc, &impl_wrap_static(cls, name, &spec))
}
FnType::Getter(ref getter) => {
impl_py_getter_def(name, doc, getter, &impl_wrap_getter(cls, name))
}
FnType::Setter(ref setter) => {
impl_py_setter_def(name, doc, setter, &impl_wrap_setter(cls, name, &spec))
}
2017-05-18 07:05:49 +00:00
}
}
2017-05-16 18:58:18 +00:00
fn check_generic(name: &syn::Ident, sig: &syn::MethodSig) {
if !sig.decl.generics.params.is_empty() {
2017-05-16 05:24:06 +00:00
panic!("python method can not be generic: {:?}", name);
}
}
pub fn body_to_result(body: &TokenStream, spec: &FnSpec) -> TokenStream {
let output = &spec.output;
quote! {
2018-07-03 18:42:02 +00:00
let _result: ::pyo3::PyResult<<#output as ::pyo3::ReturnTypeIntoPyResult>::Inner> = {
#body
};
}
}
2017-05-20 06:14:59 +00:00
/// Generate function wrapper (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_wrap(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec, noargs: bool) -> TokenStream {
let body = impl_call(cls, name, &spec);
2017-05-20 06:14:59 +00:00
if spec.args.is_empty() && noargs {
let body_to_result = body_to_result(&body, spec);
quote! {
2017-07-23 17:07:23 +00:00
unsafe extern "C" fn __wrap(
2018-06-15 20:50:26 +00:00
_slf: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject
{
2017-07-20 21:21:57 +00:00
const _LOCATION: &'static str = concat!(
stringify!(#cls), ".", stringify!(#name), "()");
2018-06-15 20:50:26 +00:00
let _pool = ::pyo3::GILPool::new();
let _py = ::pyo3::Python::assume_gil_acquired();
let _slf = _py.mut_from_borrowed_ptr::<#cls>(_slf);
2017-07-20 21:21:57 +00:00
#body_to_result
2018-06-15 20:50:26 +00:00
::pyo3::callback::cb_convert(
::pyo3::callback::PyObjectCallbackConverter, _py, _result)
}
}
} else {
let body = impl_arg_params(&spec, body);
let body_to_result = body_to_result(&body, spec);
2017-05-20 06:14:59 +00:00
quote! {
2017-07-23 17:07:23 +00:00
unsafe extern "C" fn __wrap(
2018-06-15 20:50:26 +00:00
_slf: *mut ::pyo3::ffi::PyObject,
_args: *mut ::pyo3::ffi::PyObject,
_kwargs: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject
{
2017-07-20 21:21:57 +00:00
const _LOCATION: &'static str = concat!(
stringify!(#cls), ".", stringify!(#name), "()");
2018-06-15 20:50:26 +00:00
let _pool = ::pyo3::GILPool::new();
let _py = ::pyo3::Python::assume_gil_acquired();
let _slf = _py.mut_from_borrowed_ptr::<#cls>(_slf);
2018-06-15 20:50:26 +00:00
let _args = _py.from_borrowed_ptr::<::pyo3::PyTuple>(_args);
let _kwargs = ::pyo3::argparse::get_kwargs(_py, _kwargs);
2017-07-20 21:21:57 +00:00
#body_to_result
2018-06-15 20:50:26 +00:00
::pyo3::callback::cb_convert(
::pyo3::callback::PyObjectCallbackConverter, _py, _result)
}
2017-05-20 06:14:59 +00:00
}
2017-05-16 05:24:06 +00:00
}
}
2017-05-25 05:43:07 +00:00
/// Generate function wrapper for protocol method (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_proto_wrap(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStream {
2017-05-25 05:43:07 +00:00
let cb = impl_call(cls, name, &spec);
let body = impl_arg_params(&spec, cb);
quote! {
#[allow(unused_mut)]
2017-07-23 17:07:23 +00:00
unsafe extern "C" fn __wrap(
2018-06-15 20:50:26 +00:00
_slf: *mut ::pyo3::ffi::PyObject,
_args: *mut ::pyo3::ffi::PyObject,
_kwargs: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject
2017-05-25 05:43:07 +00:00
{
2017-07-20 21:21:57 +00:00
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
2018-06-15 20:50:26 +00:00
let _pool = ::pyo3::GILPool::new();
let _py = ::pyo3::Python::assume_gil_acquired();
let _slf = _py.mut_from_borrowed_ptr::<#cls>(_slf);
2018-06-15 20:50:26 +00:00
let _args = _py.from_borrowed_ptr::<::pyo3::PyTuple>(_args);
let _kwargs = ::pyo3::argparse::get_kwargs(_py, _kwargs);
2017-07-20 21:21:57 +00:00
2017-07-23 17:07:23 +00:00
let _result = {
2017-07-20 21:21:57 +00:00
#body
};
2018-06-15 20:50:26 +00:00
::pyo3::callback::cb_convert(
::pyo3::callback::PyObjectCallbackConverter, _py, _result)
2017-05-25 05:43:07 +00:00
}
}
}
2017-05-20 06:14:59 +00:00
2017-06-08 18:29:40 +00:00
/// Generate class method wrapper (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_wrap_new(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStream {
2018-07-03 20:28:40 +00:00
let names: Vec<syn::Ident> = spec
.args
.iter()
.enumerate()
.map(|item| {
if item.1.py {
syn::Ident::new("_py", Span::call_site())
} else {
syn::Ident::new(&format!("arg{}", item.0), Span::call_site())
}
}).collect();
let cb = quote! {
2018-05-05 13:50:04 +00:00
::pyo3::ReturnTypeIntoPyResult::return_type_into_py_result(#cls::#name(&_obj, #(#names),*))
};
2017-06-08 18:29:40 +00:00
2017-05-20 06:14:59 +00:00
let body = impl_arg_params(spec, cb);
let body_to_result = body_to_result(&body, spec);
2017-05-16 05:24:06 +00:00
quote! {
#[allow(unused_mut)]
2017-07-23 17:07:23 +00:00
unsafe extern "C" fn __wrap(
2018-06-15 20:50:26 +00:00
_cls: *mut ::pyo3::ffi::PyTypeObject,
_args: *mut ::pyo3::ffi::PyObject,
_kwargs: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject
2017-05-16 05:24:06 +00:00
{
2017-08-08 07:27:33 +00:00
use pyo3::typeob::PyTypeInfo;
2017-07-20 21:21:57 +00:00
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
2018-06-15 20:50:26 +00:00
let _pool = ::pyo3::GILPool::new();
let _py = ::pyo3::Python::assume_gil_acquired();
match ::pyo3::typeob::PyRawObject::new(_py, #cls::type_object(), _cls) {
2017-08-08 07:27:33 +00:00
Ok(_obj) => {
2018-06-15 20:50:26 +00:00
let _args = _py.from_borrowed_ptr::<::pyo3::PyTuple>(_args);
let _kwargs = ::pyo3::argparse::get_kwargs(_py, _kwargs);
2017-08-08 07:27:33 +00:00
#body_to_result
2017-08-08 07:27:33 +00:00
match _result {
Ok(_) => _obj.into_ptr(),
Err(e) => {
2017-08-08 07:58:12 +00:00
e.restore(_py);
2018-07-03 19:11:56 +00:00
::std::ptr::null_mut()
2017-08-08 07:27:33 +00:00
}
}
}
Err(e) => {
2017-08-08 07:58:12 +00:00
e.restore(_py);
2018-07-03 19:11:56 +00:00
::std::ptr::null_mut()
2017-08-08 07:27:33 +00:00
}
}
2017-05-16 05:24:06 +00:00
}
}
}
2017-07-27 23:14:54 +00:00
/// Generate function wrapper for ffi::initproc
fn impl_wrap_init(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStream {
2017-07-27 23:14:54 +00:00
let cb = impl_call(cls, name, &spec);
let output = &spec.output;
let result_empty: syn::Type = parse_quote!(PyResult<()>);
let empty: syn::Type = parse_quote!(());
if output != &result_empty || output != &empty {
panic!("Constructor must return PyResult<()> or a ()");
}
2017-07-27 23:14:54 +00:00
let body = impl_arg_params(&spec, cb);
let body_to_result = body_to_result(&body, spec);
2017-07-27 23:14:54 +00:00
quote! {
#[allow(unused_mut)]
unsafe extern "C" fn __wrap(
2018-06-15 20:50:26 +00:00
_slf: *mut ::pyo3::ffi::PyObject,
_args: *mut ::pyo3::ffi::PyObject,
_kwargs: *mut ::pyo3::ffi::PyObject) -> ::pyo3::c_int
2017-07-27 23:14:54 +00:00
{
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
2018-06-15 20:50:26 +00:00
let _pool = ::pyo3::GILPool::new();
let _py = ::pyo3::Python::assume_gil_acquired();
let _slf = _py.mut_from_borrowed_ptr::<#cls>(_slf);
2018-06-15 20:50:26 +00:00
let _args = _py.from_borrowed_ptr::<::pyo3::PyTuple>(_args);
let _kwargs = ::pyo3::argparse::get_kwargs(_py, _kwargs);
2017-07-27 23:14:54 +00:00
#body_to_result
2017-07-27 23:14:54 +00:00
match _result {
Ok(_) => 0,
Err(e) => {
e.restore(_py);
-1
}
}
}
}
}
2017-06-08 18:29:40 +00:00
/// Generate class method wrapper (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_wrap_class(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStream {
2018-07-03 20:28:40 +00:00
let names: Vec<syn::Ident> = spec
.args
.iter()
.enumerate()
.map(|item| {
if item.1.py {
syn::Ident::new("_py", Span::call_site())
} else {
syn::Ident::new(&format!("arg{}", item.0), Span::call_site())
}
}).collect();
let cb = quote! {
2018-05-05 13:50:04 +00:00
::pyo3::ReturnTypeIntoPyResult::return_type_into_py_result(#cls::#name(&_cls, #(#names),*))
};
2017-06-08 18:29:40 +00:00
let body = impl_arg_params(spec, cb);
let body_to_result = body_to_result(&body, spec);
2017-06-08 18:29:40 +00:00
quote! {
#[allow(unused_mut)]
2017-07-23 17:07:23 +00:00
unsafe extern "C" fn __wrap(
2018-06-15 20:50:26 +00:00
_cls: *mut ::pyo3::ffi::PyObject,
_args: *mut ::pyo3::ffi::PyObject,
_kwargs: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject
2017-06-08 18:29:40 +00:00
{
2017-07-20 21:21:57 +00:00
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
2018-06-15 20:50:26 +00:00
let _pool = ::pyo3::GILPool::new();
let _py = ::pyo3::Python::assume_gil_acquired();
let _cls = ::pyo3::PyType::from_type_ptr(_py, _cls as *mut ::pyo3::ffi::PyTypeObject);
let _args = _py.from_borrowed_ptr::<::pyo3::PyTuple>(_args);
let _kwargs = ::pyo3::argparse::get_kwargs(_py, _kwargs);
2017-07-20 21:21:57 +00:00
#body_to_result
2018-06-15 20:50:26 +00:00
::pyo3::callback::cb_convert(
::pyo3::callback::PyObjectCallbackConverter, _py, _result)
2017-06-08 18:29:40 +00:00
}
}
}
/// Generate static method wrapper (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_wrap_static(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStream {
2018-07-03 20:28:40 +00:00
let names: Vec<syn::Ident> = spec
.args
.iter()
.enumerate()
.map(|item| {
if item.1.py {
syn::Ident::new("_py", Span::call_site())
} else {
syn::Ident::new(&format!("arg{}", item.0), Span::call_site())
}
}).collect();
let cb = quote! {
2018-05-05 13:50:04 +00:00
::pyo3::ReturnTypeIntoPyResult::return_type_into_py_result(#cls::#name(#(#names),*))
};
2017-06-08 18:29:40 +00:00
let body = impl_arg_params(spec, cb);
let body_to_result = body_to_result(&body, spec);
2017-06-08 18:29:40 +00:00
quote! {
#[allow(unused_mut)]
2017-07-23 17:07:23 +00:00
unsafe extern "C" fn __wrap(
2018-06-15 20:50:26 +00:00
_slf: *mut ::pyo3::ffi::PyObject,
_args: *mut ::pyo3::ffi::PyObject,
_kwargs: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject
2017-06-08 18:29:40 +00:00
{
2017-07-20 21:21:57 +00:00
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
2018-06-15 20:50:26 +00:00
let _pool = ::pyo3::GILPool::new();
let _py = ::pyo3::Python::assume_gil_acquired();
let _args = _py.from_borrowed_ptr::<::pyo3::PyTuple>(_args);
let _kwargs = ::pyo3::argparse::get_kwargs(_py, _kwargs);
2017-06-08 18:29:40 +00:00
#body_to_result
2018-06-15 20:50:26 +00:00
::pyo3::callback::cb_convert(
::pyo3::callback::PyObjectCallbackConverter, _py, _result)
2017-06-08 18:29:40 +00:00
}
}
}
2017-05-16 18:58:18 +00:00
/// Generate functiona wrapper (PyCFunction, PyCFunctionWithKeywords)
pub(crate) fn impl_wrap_getter(cls: &syn::Type, name: &syn::Ident) -> TokenStream {
2017-05-16 18:58:18 +00:00
quote! {
2017-07-23 17:07:23 +00:00
unsafe extern "C" fn __wrap(
2018-06-15 20:50:26 +00:00
_slf: *mut ::pyo3::ffi::PyObject, _: *mut ::pyo3::c_void) -> *mut ::pyo3::ffi::PyObject
2017-05-16 18:58:18 +00:00
{
2017-07-20 21:21:57 +00:00
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
2018-06-15 20:50:26 +00:00
let _pool = ::pyo3::GILPool::new();
let _py = ::pyo3::Python::assume_gil_acquired();
let _slf = _py.mut_from_borrowed_ptr::<#cls>(_slf);
2017-07-20 21:21:57 +00:00
2017-07-23 17:07:23 +00:00
match _slf.#name() {
2017-07-20 21:21:57 +00:00
Ok(val) => {
2017-07-23 17:07:23 +00:00
val.into_object(_py).into_ptr()
2017-07-20 21:21:57 +00:00
}
Err(e) => {
2017-07-23 17:07:23 +00:00
e.restore(_py);
2018-07-03 19:11:56 +00:00
::std::ptr::null_mut()
2017-07-20 21:21:57 +00:00
}
}
2017-05-16 18:58:18 +00:00
}
}
}
/// Generate functiona wrapper (PyCFunction, PyCFunctionWithKeywords)
pub(crate) fn impl_wrap_setter(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStream {
if spec.args.len() < 1 {
println!("Not enough arguments for setter {}::{}", quote!{#cls}, name);
}
2017-05-20 06:14:59 +00:00
let val_ty = spec.args[0].ty;
2017-05-16 18:58:18 +00:00
quote! {
#[allow(unused_mut)]
2017-07-23 17:07:23 +00:00
unsafe extern "C" fn __wrap(
2018-06-15 20:50:26 +00:00
_slf: *mut ::pyo3::ffi::PyObject,
_value: *mut ::pyo3::ffi::PyObject, _: *mut ::pyo3::c_void) -> ::pyo3::c_int
2017-05-16 18:58:18 +00:00
{
2017-07-20 21:21:57 +00:00
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
2018-06-15 20:50:26 +00:00
let _pool = ::pyo3::GILPool::new();
let _py = ::pyo3::Python::assume_gil_acquired();
let _slf = _py.mut_from_borrowed_ptr::<#cls>(_slf);
let _value = _py.from_borrowed_ptr(_value);
2017-07-20 21:21:57 +00:00
2018-06-15 20:50:26 +00:00
let _result = match <#val_ty as ::pyo3::FromPyObject>::extract(_value) {
2017-07-23 17:07:23 +00:00
Ok(_val) => _slf.#name(_val),
2017-07-20 21:21:57 +00:00
Err(e) => Err(e)
};
2017-07-23 17:07:23 +00:00
match _result {
2017-07-20 21:21:57 +00:00
Ok(_) => 0,
Err(e) => {
2017-07-23 17:07:23 +00:00
e.restore(_py);
2017-07-20 21:21:57 +00:00
-1
2017-05-25 05:43:07 +00:00
}
2017-07-20 21:21:57 +00:00
}
2017-05-16 18:58:18 +00:00
}
}
}
fn impl_call(_cls: &syn::Type, fname: &syn::Ident, spec: &FnSpec) -> TokenStream {
2018-07-03 20:28:40 +00:00
let names: Vec<syn::Ident> = spec
.args
.iter()
.enumerate()
.map(|item| {
if item.1.py {
syn::Ident::new("_py", Span::call_site())
} else {
syn::Ident::new(&format!("arg{}", item.0), Span::call_site())
}
}).collect();
quote! {
2018-05-05 13:50:04 +00:00
::pyo3::ReturnTypeIntoPyResult::return_type_into_py_result(_slf.#fname(#(#names),*))
}
2017-05-16 05:24:06 +00:00
}
pub fn impl_arg_params(spec: &FnSpec, body: TokenStream) -> TokenStream {
2018-07-03 20:28:40 +00:00
let args: Vec<FnArg> = spec
.args
.iter()
.filter(|item| !item.py)
.map(|item| item.clone())
.collect();
if args.is_empty() {
2018-07-03 20:28:40 +00:00
return body;
2017-05-25 05:43:07 +00:00
}
2017-06-18 15:00:27 +00:00
2017-05-16 05:24:06 +00:00
let mut params = Vec::new();
2017-05-20 06:14:59 +00:00
for arg in spec.args.iter() {
if arg.py {
2018-07-03 20:28:40 +00:00
continue;
}
2018-07-03 20:28:40 +00:00
if !(spec.is_args(&arg.name) || spec.is_kwargs(&arg.name)) {
let name = arg.name;
2017-06-14 05:37:26 +00:00
let kwonly = if spec.is_kw_only(&arg.name) {
syn::Ident::new("true", Span::call_site())
2017-06-14 05:37:26 +00:00
} else {
syn::Ident::new("false", Span::call_site())
2017-06-14 05:37:26 +00:00
};
2017-05-18 07:05:49 +00:00
let opt = if let Some(_) = arg.optional {
syn::Ident::new("true", Span::call_site())
2017-06-14 05:37:26 +00:00
} else if let Some(_) = spec.default_value(&arg.name) {
syn::Ident::new("true", Span::call_site())
2017-05-18 07:05:49 +00:00
} else {
syn::Ident::new("false", Span::call_site())
2017-05-18 07:05:49 +00:00
};
2017-06-14 05:37:26 +00:00
2018-07-03 20:28:40 +00:00
params.push(quote! {
::pyo3::argparse::ParamDescription{
name: stringify!(#name), is_optional: #opt, kw_only: #kwonly}
});
2017-05-18 07:05:49 +00:00
}
2017-05-16 05:24:06 +00:00
}
2018-07-03 20:28:40 +00:00
let placeholders: Vec<syn::Ident> = params
.iter()
.map(|_| syn::Ident::new("None", Span::call_site()))
.collect();
2017-05-16 05:24:06 +00:00
// generate extrat args
2017-07-23 17:07:23 +00:00
let len = spec.args.len();
2017-05-20 06:14:59 +00:00
let mut rargs = spec.args.clone();
rargs.reverse();
2017-05-16 05:24:06 +00:00
let mut body = body;
2017-07-23 17:07:23 +00:00
for (idx, arg) in rargs.iter().enumerate() {
2018-07-03 20:28:40 +00:00
body = impl_arg_param(&arg, &spec, &body, len - idx - 1);
2017-05-16 05:24:06 +00:00
}
let accept_args = syn::Ident::new(
2018-07-03 20:28:40 +00:00
if spec.accept_args() { "true" } else { "false" },
Span::call_site(),
);
let accept_kwargs = syn::Ident::new(
2018-07-03 20:28:40 +00:00
if spec.accept_kwargs() {
"true"
} else {
"false"
},
Span::call_site(),
);
2017-05-18 07:05:49 +00:00
2017-05-16 05:24:06 +00:00
// create array of arguments, and then parse
quote! {
2018-06-15 20:50:26 +00:00
const _PARAMS: &'static [::pyo3::argparse::ParamDescription<'static>] = &[
2017-05-16 05:24:06 +00:00
#(#params),*
];
2017-07-23 17:07:23 +00:00
let mut _output = [#(#placeholders),*];
2018-06-15 20:50:26 +00:00
match ::pyo3::argparse::parse_args(Some(_LOCATION), _PARAMS, &_args,
2017-07-23 17:07:23 +00:00
_kwargs, #accept_args, #accept_kwargs, &mut _output)
2017-06-07 02:26:59 +00:00
{
2017-05-16 05:24:06 +00:00
Ok(_) => {
2017-07-23 17:07:23 +00:00
let mut _iter = _output.iter();
2017-05-16 05:24:06 +00:00
#body
},
Err(err) => Err(err)
}
}
}
fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &TokenStream, idx: usize) -> TokenStream {
if arg.py {
return body.clone();
}
2017-05-16 05:24:06 +00:00
let ty = arg.ty;
let name = arg.name;
let arg_name = syn::Ident::new(&format!("arg{}", idx), Span::call_site());
2017-05-16 05:24:06 +00:00
// First unwrap() asserts the iterated sequence is long enough (which should be guaranteed);
// second unwrap() asserts the parameter was not missing (which fn
// parse_args already checked for).
2017-05-20 06:14:59 +00:00
if spec.is_args(&name) {
2017-05-16 05:24:06 +00:00
quote! {
2018-05-14 20:44:30 +00:00
<#ty as ::pyo3::FromPyObject>::extract(_args.as_ref())
.and_then(|#arg_name| {
2018-05-14 20:44:30 +00:00
#body
})
2017-05-16 05:24:06 +00:00
}
} else if spec.is_kwargs(&name) {
2017-06-24 22:28:53 +00:00
quote! {{
2017-07-23 17:07:23 +00:00
let #arg_name = _kwargs;
2017-05-18 07:05:49 +00:00
#body
2017-06-24 22:28:53 +00:00
}}
} else {
2017-05-25 05:43:07 +00:00
if let Some(_) = arg.optional {
2017-05-18 07:05:49 +00:00
// default value
let mut default = TokenStream::new();
2017-05-20 06:14:59 +00:00
if let Some(d) = spec.default_value(name) {
let dt = quote! { Some(#d) };
2017-05-18 18:15:06 +00:00
dt.to_tokens(&mut default);
2017-05-18 07:05:49 +00:00
} else {
syn::Ident::new("None", Span::call_site()).to_tokens(&mut default);
2017-05-18 07:05:49 +00:00
}
2017-06-14 05:37:26 +00:00
quote! {
match
2017-05-25 05:43:07 +00:00
match _iter.next().unwrap().as_ref() {
Some(_obj) => {
if _obj.is_none() {
Ok(#default)
2017-05-25 05:43:07 +00:00
} else {
match _obj.extract() {
Ok(_obj) => Ok(Some(_obj)),
2017-05-25 05:43:07 +00:00
Err(e) => Err(e)
}
2017-05-19 04:35:08 +00:00
}
2017-05-25 05:43:07 +00:00
},
2018-05-14 20:44:30 +00:00
None => Ok(#default)
}
{
Ok(#arg_name) => #body,
Err(e) => Err(e)
2017-05-18 07:05:49 +00:00
}
}
2017-05-20 06:14:59 +00:00
} else if let Some(default) = spec.default_value(name) {
quote! {
match match _iter.next().unwrap().as_ref() {
Some(_obj) => {
if _obj.is_none() {
Ok(#default)
} else {
match _obj.extract() {
Ok(_obj) => Ok(_obj),
Err(e) => Err(e),
2017-05-19 04:35:08 +00:00
}
2017-05-18 07:05:49 +00:00
}
},
None => Ok(#default)
} {
Ok(#arg_name) => #body,
Err(e) => Err(e)
2017-05-18 07:05:49 +00:00
}
}
} else {
quote! {
2018-05-14 20:44:30 +00:00
::pyo3::ObjectProtocol::extract(_iter.next().unwrap().unwrap())
.and_then(|#arg_name| {
#body
})
2017-05-18 07:05:49 +00:00
}
}
}
}
2018-07-03 20:28:40 +00:00
pub fn impl_py_method_def(
name: &syn::Ident,
doc: syn::Lit,
spec: &FnSpec,
wrapper: &TokenStream,
) -> TokenStream {
if spec.args.is_empty() {
quote! {
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDefType::Method({
#wrapper
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDef {
ml_name: stringify!(#name),
2018-06-15 20:50:26 +00:00
ml_meth: ::pyo3::class::PyMethodType::PyNoArgsFunction(__wrap),
ml_flags: ::pyo3::ffi::METH_NOARGS,
2017-06-13 04:08:59 +00:00
ml_doc: #doc,
}
})
}
} else {
quote! {
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDefType::Method({
#wrapper
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDef {
ml_name: stringify!(#name),
2018-06-15 20:50:26 +00:00
ml_meth: ::pyo3::class::PyMethodType::PyCFunctionWithKeywords(__wrap),
ml_flags: ::pyo3::ffi::METH_VARARGS | ::pyo3::ffi::METH_KEYWORDS,
2017-06-13 04:08:59 +00:00
ml_doc: #doc,
}
})
}
2017-05-18 07:05:49 +00:00
}
}
2018-07-03 20:28:40 +00:00
pub fn impl_py_method_def_new(
name: &syn::Ident,
doc: syn::Lit,
wrapper: &TokenStream,
) -> TokenStream {
2017-05-20 06:14:59 +00:00
quote! {
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDefType::New({
2017-05-20 06:14:59 +00:00
#wrapper
2017-05-18 07:05:49 +00:00
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDef {
2017-05-20 06:14:59 +00:00
ml_name: stringify!(#name),
2018-06-15 20:50:26 +00:00
ml_meth: ::pyo3::class::PyMethodType::PyNewFunc(__wrap),
ml_flags: ::pyo3::ffi::METH_VARARGS | ::pyo3::ffi::METH_KEYWORDS,
2017-06-13 04:08:59 +00:00
ml_doc: #doc,
2017-05-20 06:14:59 +00:00
}
})
2017-05-18 07:05:49 +00:00
}
2017-05-16 05:24:06 +00:00
}
2018-07-03 20:28:40 +00:00
pub fn impl_py_method_def_init(
name: &syn::Ident,
doc: syn::Lit,
wrapper: &TokenStream,
) -> TokenStream {
2017-07-27 23:14:54 +00:00
quote! {
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDefType::Init({
2017-07-27 23:14:54 +00:00
#wrapper
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDef {
2017-07-27 23:14:54 +00:00
ml_name: stringify!(#name),
2018-06-15 20:50:26 +00:00
ml_meth: ::pyo3::class::PyMethodType::PyInitFunc(__wrap),
ml_flags: ::pyo3::ffi::METH_VARARGS | ::pyo3::ffi::METH_KEYWORDS,
2017-07-27 23:14:54 +00:00
ml_doc: #doc,
}
})
}
}
2018-07-03 20:28:40 +00:00
pub fn impl_py_method_def_class(
name: &syn::Ident,
doc: syn::Lit,
wrapper: &TokenStream,
) -> TokenStream {
2017-06-08 18:29:40 +00:00
quote! {
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDefType::Class({
2017-06-08 18:29:40 +00:00
#wrapper
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDef {
2017-06-08 18:29:40 +00:00
ml_name: stringify!(#name),
2018-06-15 20:50:26 +00:00
ml_meth: ::pyo3::class::PyMethodType::PyCFunctionWithKeywords(__wrap),
ml_flags: ::pyo3::ffi::METH_VARARGS | ::pyo3::ffi::METH_KEYWORDS |
::pyo3::ffi::METH_CLASS,
2017-06-13 04:08:59 +00:00
ml_doc: #doc,
2017-06-08 18:29:40 +00:00
}
})
}
}
2018-07-03 20:28:40 +00:00
pub fn impl_py_method_def_static(
name: &syn::Ident,
doc: syn::Lit,
wrapper: &TokenStream,
) -> TokenStream {
2017-06-08 18:29:40 +00:00
quote! {
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDefType::Static({
2017-06-08 18:29:40 +00:00
#wrapper
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDef {
2017-06-08 18:29:40 +00:00
ml_name: stringify!(#name),
2018-06-15 20:50:26 +00:00
ml_meth: ::pyo3::class::PyMethodType::PyCFunctionWithKeywords(__wrap),
ml_flags: ::pyo3::ffi::METH_VARARGS | ::pyo3::ffi::METH_KEYWORDS | ::pyo3::ffi::METH_STATIC,
2017-06-13 04:08:59 +00:00
ml_doc: #doc,
2017-06-08 18:29:40 +00:00
}
})
}
}
2018-07-03 20:28:40 +00:00
pub fn impl_py_method_def_call(
name: &syn::Ident,
doc: syn::Lit,
wrapper: &TokenStream,
) -> TokenStream {
2017-05-16 18:58:18 +00:00
quote! {
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDefType::Call({
2017-05-16 18:58:18 +00:00
#wrapper
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDef {
2017-05-16 18:58:18 +00:00
ml_name: stringify!(#name),
2018-06-15 20:50:26 +00:00
ml_meth: ::pyo3::class::PyMethodType::PyCFunctionWithKeywords(__wrap),
ml_flags: ::pyo3::ffi::METH_VARARGS | ::pyo3::ffi::METH_KEYWORDS,
2017-06-13 04:08:59 +00:00
ml_doc: #doc,
2017-05-16 18:58:18 +00:00
}
})
}
}
2018-07-03 20:28:40 +00:00
pub(crate) fn impl_py_setter_def(
name: &syn::Ident,
doc: syn::Lit,
setter: &Option<String>,
wrapper: &TokenStream,
) -> TokenStream {
2017-05-20 06:14:59 +00:00
let n = if let &Some(ref name) = setter {
2017-05-16 18:58:18 +00:00
name.to_string()
} else {
let n = name.to_string();
2017-05-16 18:58:18 +00:00
if n.starts_with("set_") {
n[4..].to_string()
} else {
n
}
};
quote! {
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDefType::Setter({
2017-05-16 18:58:18 +00:00
#wrapper
2018-06-15 20:50:26 +00:00
::pyo3::class::PySetterDef {
2017-05-16 18:58:18 +00:00
name: #n,
2017-07-23 17:07:23 +00:00
meth: __wrap,
2017-06-13 04:08:59 +00:00
doc: #doc,
2017-05-16 18:58:18 +00:00
}
})
}
}
2018-07-03 20:28:40 +00:00
pub(crate) fn impl_py_getter_def(
name: &syn::Ident,
doc: syn::Lit,
getter: &Option<String>,
wrapper: &TokenStream,
) -> TokenStream {
2017-05-20 06:14:59 +00:00
let n = if let &Some(ref name) = getter {
2017-05-16 18:58:18 +00:00
name.to_string()
} else {
let n = name.to_string();
2017-05-16 18:58:18 +00:00
if n.starts_with("get_") {
n[4..].to_string()
} else {
n
2017-05-16 05:24:06 +00:00
}
2017-05-16 18:58:18 +00:00
};
quote! {
2018-06-15 20:50:26 +00:00
::pyo3::class::PyMethodDefType::Getter({
2017-05-16 18:58:18 +00:00
#wrapper
2018-06-15 20:50:26 +00:00
::pyo3::class::PyGetterDef {
2017-05-16 18:58:18 +00:00
name: #n,
2017-07-23 17:07:23 +00:00
meth: __wrap,
2017-06-13 04:08:59 +00:00
doc: #doc,
2017-05-16 18:58:18 +00:00
}
})
}
2017-05-16 05:24:06 +00:00
}