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)