1use crate::ffi_ptr_ext::FfiPtrExt as _;
4use crate::types::{PyAnyMethods as _, PyDict, PyString, PyTuple};
5use crate::{ffi, Borrowed, Bound, IntoPyObjectExt as _, Py, PyAny, PyResult};
6
7pub(crate) mod private {
8 use super::*;
9
10 pub trait Sealed {}
11
12 impl Sealed for () {}
13 impl Sealed for Bound<'_, PyTuple> {}
14 impl Sealed for Py<PyTuple> {}
15
16 pub struct Token;
17}
18
19#[cfg_attr(
44 diagnostic_namespace,
45 diagnostic::on_unimplemented(
46 message = "`{Self}` cannot used as a Python `call` argument",
47 note = "`PyCallArgs` is implemented for Rust tuples, `Bound<'py, PyTuple>` and `Py<PyTuple>`",
48 note = "if your type is convertable to `PyTuple` via `IntoPyObject`, call `<arg>.into_pyobject(py)` manually",
49 note = "if you meant to pass the type as a single argument, wrap it in a 1-tuple, `(<arg>,)`"
50 )
51)]
52pub trait PyCallArgs<'py>: Sized + private::Sealed {
53 #[doc(hidden)]
54 fn call(
55 self,
56 function: Borrowed<'_, 'py, PyAny>,
57 kwargs: Borrowed<'_, 'py, PyDict>,
58 token: private::Token,
59 ) -> PyResult<Bound<'py, PyAny>>;
60
61 #[doc(hidden)]
62 fn call_positional(
63 self,
64 function: Borrowed<'_, 'py, PyAny>,
65 token: private::Token,
66 ) -> PyResult<Bound<'py, PyAny>>;
67
68 #[doc(hidden)]
69 fn call_method_positional(
70 self,
71 object: Borrowed<'_, 'py, PyAny>,
72 method_name: Borrowed<'_, 'py, PyString>,
73 _: private::Token,
74 ) -> PyResult<Bound<'py, PyAny>> {
75 object
76 .getattr(method_name)
77 .and_then(|method| method.call1(self))
78 }
79}
80
81impl<'py> PyCallArgs<'py> for () {
82 fn call(
83 self,
84 function: Borrowed<'_, 'py, PyAny>,
85 kwargs: Borrowed<'_, 'py, PyDict>,
86 token: private::Token,
87 ) -> PyResult<Bound<'py, PyAny>> {
88 let args = self.into_pyobject_or_pyerr(function.py())?;
89 args.call(function, kwargs, token)
90 }
91
92 fn call_positional(
93 self,
94 function: Borrowed<'_, 'py, PyAny>,
95 token: private::Token,
96 ) -> PyResult<Bound<'py, PyAny>> {
97 let args = self.into_pyobject_or_pyerr(function.py())?;
98 args.call_positional(function, token)
99 }
100}
101
102impl<'py> PyCallArgs<'py> for Bound<'py, PyTuple> {
103 fn call(
104 self,
105 function: Borrowed<'_, 'py, PyAny>,
106 kwargs: Borrowed<'_, '_, PyDict>,
107 _: private::Token,
108 ) -> 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 }
113 }
114
115 fn call_positional(
116 self,
117 function: Borrowed<'_, 'py, PyAny>,
118 _: private::Token,
119 ) -> 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 }
124 }
125}
126
127impl<'py> PyCallArgs<'py> for Py<PyTuple> {
128 fn call(
129 self,
130 function: Borrowed<'_, 'py, PyAny>,
131 kwargs: Borrowed<'_, '_, PyDict>,
132 _: private::Token,
133 ) -> PyResult<Bound<'py, PyAny>> {
134 unsafe {
135 ffi::PyObject_Call(function.as_ptr(), self.as_ptr(), kwargs.as_ptr())
136 .assume_owned_or_err(function.py())
137 }
138 }
139
140 fn call_positional(
141 self,
142 function: Borrowed<'_, 'py, PyAny>,
143 _: private::Token,
144 ) -> PyResult<Bound<'py, PyAny>> {
145 unsafe {
146 ffi::PyObject_Call(function.as_ptr(), self.as_ptr(), std::ptr::null_mut())
147 .assume_owned_or_err(function.py())
148 }
149 }
150}