Skip to content

Commit 67b1a61

Browse files
authored
Merge pull request #1455 from PyO3/generate-less-code
Generate less code
2 parents f9ad119 + 19bcce5 commit 67b1a61

File tree

5 files changed

+69
-55
lines changed

5 files changed

+69
-55
lines changed

pyo3-macros-backend/src/module.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub fn py_init(fnname: &Ident, name: &Ident, doc: syn::LitStr) -> TokenStream {
2525
const NAME: &'static str = concat!(stringify!(#name), "\0");
2626
static MODULE_DEF: ModuleDef = unsafe { ModuleDef::new(NAME) };
2727

28-
pyo3::callback_body!(_py, { MODULE_DEF.make_module(#doc, #fnname) })
28+
pyo3::callback::handle_panic(|_py| { MODULE_DEF.make_module(#doc, #fnname) })
2929
}
3030
}
3131
}
@@ -229,14 +229,14 @@ fn function_c_wrapper(
229229
let slf_module;
230230
if pass_module {
231231
cb = quote! {
232-
#name(_slf, #(#names),*)
232+
pyo3::callback::convert(_py, #name(_slf, #(#names),*))
233233
};
234234
slf_module = Some(quote! {
235235
let _slf = _py.from_borrowed_ptr::<pyo3::types::PyModule>(_slf);
236236
});
237237
} else {
238238
cb = quote! {
239-
#name(#(#names),*)
239+
pyo3::callback::convert(_py, #name(#(#names),*))
240240
};
241241
slf_module = None;
242242
};
@@ -248,7 +248,7 @@ fn function_c_wrapper(
248248
_kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject
249249
{
250250
const _LOCATION: &'static str = concat!(stringify!(#name), "()");
251-
pyo3::callback_body!(_py, {
251+
pyo3::callback::handle_panic(|_py| {
252252
#slf_module
253253
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
254254
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);

pyo3-macros-backend/src/pyclass.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,8 @@ fn impl_class(
428428

429429
fn for_each_method_def(visitor: impl FnMut(&pyo3::class::PyMethodDefType)) {
430430
use pyo3::class::impl_::*;
431-
let collector = PyClassImplCollector::<#cls>::new();
432-
pyo3::inventory::iter::<<#cls as pyo3::class::methods::HasMethodsInventory>::Methods>
431+
let collector = PyClassImplCollector::<Self>::new();
432+
pyo3::inventory::iter::<<Self as pyo3::class::methods::HasMethodsInventory>::Methods>
433433
.into_iter()
434434
.flat_map(pyo3::class::methods::PyMethodsInventory::get)
435435
.chain(collector.object_protocol_methods())
@@ -442,19 +442,19 @@ fn impl_class(
442442
}
443443
fn get_new() -> Option<pyo3::ffi::newfunc> {
444444
use pyo3::class::impl_::*;
445-
let collector = PyClassImplCollector::<#cls>::new();
445+
let collector = PyClassImplCollector::<Self>::new();
446446
collector.new_impl()
447447
}
448448
fn get_call() -> Option<pyo3::ffi::PyCFunctionWithKeywords> {
449449
use pyo3::class::impl_::*;
450-
let collector = PyClassImplCollector::<#cls>::new();
450+
let collector = PyClassImplCollector::<Self>::new();
451451
collector.call_impl()
452452
}
453453

454454
fn for_each_proto_slot(visitor: impl FnMut(&pyo3::ffi::PyType_Slot)) {
455455
// Implementation which uses dtolnay specialization to load all slots.
456456
use pyo3::class::impl_::*;
457-
let collector = PyClassImplCollector::<#cls>::new();
457+
let collector = PyClassImplCollector::<Self>::new();
458458
collector.object_protocol_slots()
459459
.iter()
460460
.chain(collector.number_protocol_slots())
@@ -470,7 +470,7 @@ fn impl_class(
470470

471471
fn get_buffer() -> Option<&'static pyo3::class::impl_::PyBufferProcs> {
472472
use pyo3::class::impl_::*;
473-
let collector = PyClassImplCollector::<#cls>::new();
473+
let collector = PyClassImplCollector::<Self>::new();
474474
collector.buffer_procs()
475475
}
476476
}

pyo3-macros-backend/src/pymethod.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,9 @@ fn impl_wrap_common(
121121
{
122122
const _LOCATION: &'static str = concat!(
123123
stringify!(#cls), ".", stringify!(#python_name), "()");
124-
pyo3::callback_body_without_convert!(_py, {
124+
pyo3::callback::handle_panic(|_py| {
125125
#slf
126-
pyo3::callback::convert(_py, #body)
126+
#body
127127
})
128128
}
129129
}
@@ -138,12 +138,12 @@ fn impl_wrap_common(
138138
{
139139
const _LOCATION: &'static str = concat!(
140140
stringify!(#cls), ".", stringify!(#python_name), "()");
141-
pyo3::callback_body_without_convert!(_py, {
141+
pyo3::callback::handle_panic(|_py| {
142142
#slf
143143
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
144144
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);
145145

146-
pyo3::callback::convert(_py, #body)
146+
#body
147147
})
148148
}
149149
}
@@ -165,12 +165,12 @@ pub fn impl_proto_wrap(cls: &syn::Type, spec: &FnSpec<'_>, self_ty: &SelfType) -
165165
_kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject
166166
{
167167
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
168-
pyo3::callback_body_without_convert!(_py, {
168+
pyo3::callback::handle_panic(|_py| {
169169
#slf
170170
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
171171
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);
172172

173-
pyo3::callback::convert(_py, #body)
173+
#body
174174
})
175175
}
176176
}
@@ -196,7 +196,7 @@ pub fn impl_wrap_new(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
196196
use std::convert::TryFrom;
197197

198198
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
199-
pyo3::callback_body_without_convert!(_py, {
199+
pyo3::callback::handle_panic(|_py| {
200200
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
201201
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);
202202

@@ -213,7 +213,7 @@ pub fn impl_wrap_class(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
213213
let name = &spec.name;
214214
let python_name = &spec.python_name;
215215
let names: Vec<syn::Ident> = get_arg_names(&spec);
216-
let cb = quote! { #cls::#name(&_cls, #(#names),*) };
216+
let cb = quote! { pyo3::callback::convert(_py, #cls::#name(&_cls, #(#names),*)) };
217217

218218
let body = impl_arg_params(spec, Some(cls), cb);
219219

@@ -225,12 +225,12 @@ pub fn impl_wrap_class(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
225225
_kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject
226226
{
227227
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
228-
pyo3::callback_body_without_convert!(_py, {
228+
pyo3::callback::handle_panic(|_py| {
229229
let _cls = pyo3::types::PyType::from_type_ptr(_py, _cls as *mut pyo3::ffi::PyTypeObject);
230230
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
231231
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);
232232

233-
pyo3::callback::convert(_py, #body)
233+
#body
234234
})
235235
}
236236
}
@@ -241,7 +241,7 @@ pub fn impl_wrap_static(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
241241
let name = &spec.name;
242242
let python_name = &spec.python_name;
243243
let names: Vec<syn::Ident> = get_arg_names(&spec);
244-
let cb = quote! { #cls::#name(#(#names),*) };
244+
let cb = quote! { pyo3::callback::convert(_py, #cls::#name(#(#names),*)) };
245245

246246
let body = impl_arg_params(spec, Some(cls), cb);
247247

@@ -253,11 +253,11 @@ pub fn impl_wrap_static(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
253253
_kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject
254254
{
255255
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
256-
pyo3::callback_body_without_convert!(_py, {
256+
pyo3::callback::handle_panic(|_py| {
257257
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
258258
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);
259259

260-
pyo3::callback::convert(_py, #body)
260+
#body
261261
})
262262
}
263263
}
@@ -319,7 +319,7 @@ pub(crate) fn impl_wrap_getter(
319319
_slf: *mut pyo3::ffi::PyObject, _: *mut std::os::raw::c_void) -> *mut pyo3::ffi::PyObject
320320
{
321321
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
322-
pyo3::callback_body_without_convert!(_py, {
322+
pyo3::callback::handle_panic(|_py| {
323323
#slf
324324
pyo3::callback::convert(_py, #getter_impl)
325325
})
@@ -371,7 +371,7 @@ pub(crate) fn impl_wrap_setter(
371371
_value: *mut pyo3::ffi::PyObject, _: *mut std::os::raw::c_void) -> std::os::raw::c_int
372372
{
373373
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
374-
pyo3::callback_body_without_convert!(_py, {
374+
pyo3::callback::handle_panic(|_py| {
375375
#slf
376376
let _value = _py.from_borrowed_ptr::<pyo3::types::PyAny>(_value);
377377
let _val = pyo3::FromPyObject::extract(_value)?;
@@ -392,7 +392,7 @@ pub fn get_arg_names(spec: &FnSpec) -> Vec<syn::Ident> {
392392
fn impl_call(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
393393
let fname = &spec.name;
394394
let names = get_arg_names(spec);
395-
quote! { #cls::#fname(_slf, #(#names),*) }
395+
quote! { pyo3::callback::convert(_py, #cls::#fname(_slf, #(#names),*)) }
396396
}
397397

398398
pub fn impl_arg_params(

src/callback.rs

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::IntoPyPointer;
99
use crate::{IntoPy, PyObject, Python};
1010
use std::isize;
1111
use std::os::raw::c_int;
12+
use std::panic::UnwindSafe;
1213

1314
/// A type which can be the return type of a python C-API callback
1415
pub trait PyCallbackOutput: Copy {
@@ -194,9 +195,9 @@ where
194195
#[doc(hidden)]
195196
#[macro_export]
196197
macro_rules! callback_body {
197-
($py:ident, $body:expr) => {{
198-
$crate::callback_body_without_convert!($py, $crate::callback::convert($py, $body))
199-
}};
198+
($py:ident, $body:expr) => {
199+
$crate::callback::handle_panic(|$py| $crate::callback::convert($py, $body))
200+
};
200201
}
201202

202203
/// Variant of the above which does not perform the callback conversion. This allows the callback
@@ -210,12 +211,12 @@ macro_rules! callback_body {
210211
/// }
211212
/// ```
212213
///
213-
/// It is wrapped in proc macros with callback_body_without_convert like so:
214+
/// It is wrapped in proc macros with handle_panic like so:
214215
///
215216
/// ```ignore
216-
/// pyo3::callback_body_without_convert!(py, {
217+
/// pyo3::callback::handle_panic(|_py| {
217218
/// let _slf = #slf;
218-
/// pyo3::callback::convert(py, #foo)
219+
/// pyo3::callback::convert(_py, #foo)
219220
/// })
220221
/// ```
221222
///
@@ -231,33 +232,32 @@ macro_rules! callback_body {
231232
/// Then this will fail to compile, because the result of #foo borrows _slf, but _slf drops when
232233
/// the block passed to the macro ends.
233234
#[doc(hidden)]
234-
#[macro_export]
235-
macro_rules! callback_body_without_convert {
236-
($py:ident, $body:expr) => {{
237-
let pool = $crate::GILPool::new();
238-
let unwind_safe_py = std::panic::AssertUnwindSafe(pool.python());
239-
let result = match std::panic::catch_unwind(move || -> $crate::PyResult<_> {
240-
let $py = *unwind_safe_py;
241-
$body
242-
}) {
235+
pub unsafe fn handle_panic<F, R>(body: F) -> R
236+
where
237+
F: FnOnce(Python) -> crate::PyResult<R> + UnwindSafe,
238+
R: PyCallbackOutput,
239+
{
240+
let pool = crate::GILPool::new();
241+
let unwind_safe_py = std::panic::AssertUnwindSafe(pool.python());
242+
let result =
243+
match std::panic::catch_unwind(move || -> crate::PyResult<_> { body(*unwind_safe_py) }) {
243244
Ok(result) => result,
244245
Err(e) => {
245246
// Try to format the error in the same way panic does
246247
if let Some(string) = e.downcast_ref::<String>() {
247-
Err($crate::panic::PanicException::new_err((string.clone(),)))
248+
Err(crate::panic::PanicException::new_err((string.clone(),)))
248249
} else if let Some(s) = e.downcast_ref::<&str>() {
249-
Err($crate::panic::PanicException::new_err((s.to_string(),)))
250+
Err(crate::panic::PanicException::new_err((s.to_string(),)))
250251
} else {
251-
Err($crate::panic::PanicException::new_err((
252+
Err(crate::panic::PanicException::new_err((
252253
"panic from Rust code",
253254
)))
254255
}
255256
}
256257
};
257258

258-
result.unwrap_or_else(|e| {
259-
e.restore(pool.python());
260-
$crate::callback::callback_error()
261-
})
262-
}};
259+
result.unwrap_or_else(|e| {
260+
e.restore(pool.python());
261+
crate::callback::callback_error()
262+
})
263263
}

tests/ui/static_ref.stderr

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
1-
error[E0597]: `pool` does not live long enough
1+
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'p` due to conflicting requirements
22
--> $DIR/static_ref.rs:4:1
33
|
44
4 | #[pyfunction]
55
| ^^^^^^^^^^^^^
6-
| |
7-
| borrowed value does not live long enough
8-
| `pool` dropped here while still borrowed
9-
| cast requires that `pool` is borrowed for `'static`
106
|
11-
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
7+
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 4:1...
8+
--> $DIR/static_ref.rs:4:1
9+
|
10+
4 | #[pyfunction]
11+
| ^^^^^^^^^^^^^
12+
note: ...so that the types are compatible
13+
--> $DIR/static_ref.rs:4:1
14+
|
15+
4 | #[pyfunction]
16+
| ^^^^^^^^^^^^^
17+
= note: expected `pyo3::Python<'_>`
18+
found `pyo3::Python<'_>`
19+
= note: but, the lifetime must be valid for the static lifetime...
20+
note: ...so that reference does not outlive borrowed content
21+
--> $DIR/static_ref.rs:4:1
22+
|
23+
4 | #[pyfunction]
24+
| ^^^^^^^^^^^^^
25+
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

0 commit comments

Comments
 (0)