Skip to content

Commit 1b00b0d

Browse files
authored
implement PyCallArgs for borrowed types (#5013)
* implement `PyCallArgs` for borrowed types * pass token * clippy
1 parent 5caaa37 commit 1b00b0d

File tree

2 files changed

+179
-13
lines changed

2 files changed

+179
-13
lines changed

newsfragments/5013.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Implement `PyCallArgs` for `Borrowed<'_, 'py, PyTuple>`, `&Bound<'py, PyTuple>`, and `&Py<PyTuple>`.

src/call.rs

Lines changed: 178 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ pub(crate) mod private {
1111

1212
impl Sealed for () {}
1313
impl Sealed for Bound<'_, PyTuple> {}
14+
impl Sealed for &'_ Bound<'_, PyTuple> {}
1415
impl Sealed for Py<PyTuple> {}
15-
16+
impl Sealed for &'_ Py<PyTuple> {}
17+
impl Sealed for Borrowed<'_, '_, PyTuple> {}
1618
pub struct Token;
1719
}
1820

@@ -100,35 +102,99 @@ impl<'py> PyCallArgs<'py> for () {
100102
}
101103

102104
impl<'py> PyCallArgs<'py> for Bound<'py, PyTuple> {
105+
#[inline]
103106
fn call(
104107
self,
105108
function: Borrowed<'_, 'py, PyAny>,
106-
kwargs: Borrowed<'_, '_, PyDict>,
107-
_: private::Token,
109+
kwargs: Borrowed<'_, 'py, PyDict>,
110+
token: private::Token,
108111
) -> PyResult<Bound<'py, PyAny>> {
109-
unsafe {
110-
ffi::PyObject_Call(function.as_ptr(), self.as_ptr(), kwargs.as_ptr())
111-
.assume_owned_or_err(function.py())
112-
}
112+
self.as_borrowed().call(function, kwargs, token)
113113
}
114114

115+
#[inline]
115116
fn call_positional(
116117
self,
117118
function: Borrowed<'_, 'py, PyAny>,
118-
_: private::Token,
119+
token: private::Token,
119120
) -> PyResult<Bound<'py, PyAny>> {
120-
unsafe {
121-
ffi::PyObject_Call(function.as_ptr(), self.as_ptr(), std::ptr::null_mut())
122-
.assume_owned_or_err(function.py())
123-
}
121+
self.as_borrowed().call_positional(function, token)
122+
}
123+
}
124+
125+
impl<'py> PyCallArgs<'py> for &'_ Bound<'py, PyTuple> {
126+
#[inline]
127+
fn call(
128+
self,
129+
function: Borrowed<'_, 'py, PyAny>,
130+
kwargs: Borrowed<'_, 'py, PyDict>,
131+
token: private::Token,
132+
) -> PyResult<Bound<'py, PyAny>> {
133+
self.as_borrowed().call(function, kwargs, token)
134+
}
135+
136+
#[inline]
137+
fn call_positional(
138+
self,
139+
function: Borrowed<'_, 'py, PyAny>,
140+
token: private::Token,
141+
) -> PyResult<Bound<'py, PyAny>> {
142+
self.as_borrowed().call_positional(function, token)
124143
}
125144
}
126145

127146
impl<'py> PyCallArgs<'py> for Py<PyTuple> {
147+
#[inline]
128148
fn call(
129149
self,
130150
function: Borrowed<'_, 'py, PyAny>,
131-
kwargs: Borrowed<'_, '_, PyDict>,
151+
kwargs: Borrowed<'_, 'py, PyDict>,
152+
token: private::Token,
153+
) -> PyResult<Bound<'py, PyAny>> {
154+
self.bind_borrowed(function.py())
155+
.call(function, kwargs, token)
156+
}
157+
158+
#[inline]
159+
fn call_positional(
160+
self,
161+
function: Borrowed<'_, 'py, PyAny>,
162+
token: private::Token,
163+
) -> PyResult<Bound<'py, PyAny>> {
164+
self.bind_borrowed(function.py())
165+
.call_positional(function, token)
166+
}
167+
}
168+
169+
impl<'py> PyCallArgs<'py> for &'_ Py<PyTuple> {
170+
#[inline]
171+
fn call(
172+
self,
173+
function: Borrowed<'_, 'py, PyAny>,
174+
kwargs: Borrowed<'_, 'py, PyDict>,
175+
token: private::Token,
176+
) -> PyResult<Bound<'py, PyAny>> {
177+
self.bind_borrowed(function.py())
178+
.call(function, kwargs, token)
179+
}
180+
181+
#[inline]
182+
fn call_positional(
183+
self,
184+
function: Borrowed<'_, 'py, PyAny>,
185+
token: private::Token,
186+
) -> PyResult<Bound<'py, PyAny>> {
187+
self.bind_borrowed(function.py())
188+
.call_positional(function, token)
189+
}
190+
}
191+
192+
impl<'py> PyCallArgs<'py> for Borrowed<'_, 'py, PyTuple> {
193+
#[inline]
194+
fn call(
195+
self,
196+
function: Borrowed<'_, 'py, PyAny>,
197+
kwargs: Borrowed<'_, 'py, PyDict>,
132198
_: private::Token,
133199
) -> PyResult<Bound<'py, PyAny>> {
134200
unsafe {
@@ -137,6 +203,7 @@ impl<'py> PyCallArgs<'py> for Py<PyTuple> {
137203
}
138204
}
139205

206+
#[inline]
140207
fn call_positional(
141208
self,
142209
function: Borrowed<'_, 'py, PyAny>,
@@ -148,3 +215,101 @@ impl<'py> PyCallArgs<'py> for Py<PyTuple> {
148215
}
149216
}
150217
}
218+
219+
#[cfg(test)]
220+
#[cfg(feature = "macros")]
221+
mod tests {
222+
use crate::{
223+
pyfunction,
224+
types::{PyDict, PyTuple},
225+
Py,
226+
};
227+
228+
#[pyfunction(signature = (*args, **kwargs), crate = "crate")]
229+
fn args_kwargs(
230+
args: Py<PyTuple>,
231+
kwargs: Option<Py<PyDict>>,
232+
) -> (Py<PyTuple>, Option<Py<PyDict>>) {
233+
(args, kwargs)
234+
}
235+
236+
#[test]
237+
fn test_call() {
238+
use crate::{
239+
types::{IntoPyDict, PyAnyMethods, PyDict, PyTuple},
240+
wrap_pyfunction, Py, Python,
241+
};
242+
243+
Python::with_gil(|py| {
244+
let f = wrap_pyfunction!(args_kwargs, py).unwrap();
245+
246+
let args = PyTuple::new(py, [1, 2, 3]).unwrap();
247+
let kwargs = &[("foo", 1), ("bar", 2)].into_py_dict(py).unwrap();
248+
249+
macro_rules! check_call {
250+
($args:expr, $kwargs:expr) => {
251+
let (a, k): (Py<PyTuple>, Py<PyDict>) = f
252+
.call(args.clone(), Some(kwargs))
253+
.unwrap()
254+
.extract()
255+
.unwrap();
256+
assert!(a.is(&args));
257+
assert!(k.is(kwargs));
258+
};
259+
}
260+
261+
// Bound<'py, PyTuple>
262+
check_call!(args.clone(), kwargs);
263+
264+
// &Bound<'py, PyTuple>
265+
check_call!(&args, kwargs);
266+
267+
// Py<PyTuple>
268+
check_call!(args.clone().unbind(), kwargs);
269+
270+
// &Py<PyTuple>
271+
check_call!(&args.as_unbound(), kwargs);
272+
273+
// Borrowed<'_, '_, PyTuple>
274+
check_call!(args.as_borrowed(), kwargs);
275+
})
276+
}
277+
278+
#[test]
279+
fn test_call_positional() {
280+
use crate::{
281+
types::{PyAnyMethods, PyNone, PyTuple},
282+
wrap_pyfunction, Py, Python,
283+
};
284+
285+
Python::with_gil(|py| {
286+
let f = wrap_pyfunction!(args_kwargs, py).unwrap();
287+
288+
let args = PyTuple::new(py, [1, 2, 3]).unwrap();
289+
290+
macro_rules! check_call {
291+
($args:expr, $kwargs:expr) => {
292+
let (a, k): (Py<PyTuple>, Py<PyNone>) =
293+
f.call1(args.clone()).unwrap().extract().unwrap();
294+
assert!(a.is(&args));
295+
assert!(k.is_none(py));
296+
};
297+
}
298+
299+
// Bound<'py, PyTuple>
300+
check_call!(args.clone(), kwargs);
301+
302+
// &Bound<'py, PyTuple>
303+
check_call!(&args, kwargs);
304+
305+
// Py<PyTuple>
306+
check_call!(args.clone().unbind(), kwargs);
307+
308+
// &Py<PyTuple>
309+
check_call!(args.as_unbound(), kwargs);
310+
311+
// Borrowed<'_, '_, PyTuple>
312+
check_call!(args.as_borrowed(), kwargs);
313+
})
314+
}
315+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy