Add `Py::bind`, `Py::into_bound`, and `Py::bind_borrowed`

This commit is contained in:
David Hewitt 2023-12-21 13:00:14 +00:00
parent 0f242c399d
commit e8e6fb93d7
7 changed files with 45 additions and 44 deletions

View File

@ -832,17 +832,18 @@ where
impl<T> Py<T> {
/// Attaches this `Py` to the given Python context, allowing access to further Python APIs.
pub(crate) fn attach<'py>(&self, _py: Python<'py>) -> &Bound<'py, T> {
pub fn bind<'py>(&self, _py: Python<'py>) -> &Bound<'py, T> {
// Safety: `Bound` has the same layout as `Py`
unsafe { &*(self as *const Py<T>).cast() }
}
/// Same as `attach` but takes ownership of `self`.
pub(crate) fn attach_into(self, py: Python<'_>) -> Bound<'_, T> {
/// Same as `bind` but takes ownership of `self`.
pub fn into_bound(self, py: Python<'_>) -> Bound<'_, T> {
Bound(py, ManuallyDrop::new(self))
}
pub(crate) fn attach_borrow<'a, 'py>(&'a self, py: Python<'py>) -> Borrowed<'a, 'py, T> {
/// Same as `bind` but produces a `Borrowed<T>` instead of a `Bound<T>`.
pub fn bind_borrowed<'a, 'py>(&'a self, py: Python<'py>) -> Borrowed<'a, 'py, T> {
Borrowed(self.0, PhantomData, py)
}
@ -957,7 +958,7 @@ impl<T> Py<T> {
where
N: IntoPy<Py<PyString>>,
{
self.attach(py).as_any().getattr(attr_name).map(Into::into)
self.bind(py).as_any().getattr(attr_name).map(Into::into)
}
/// Sets an attribute value.
@ -987,9 +988,9 @@ impl<T> Py<T> {
N: IntoPy<Py<PyString>>,
V: IntoPy<Py<PyAny>>,
{
self.attach(py)
self.bind(py)
.as_any()
.setattr(attr_name, value.into_py(py).attach_into(py))
.setattr(attr_name, value.into_py(py).into_bound(py))
}
/// Calls the object.
@ -1001,21 +1002,21 @@ impl<T> Py<T> {
args: impl IntoPy<Py<PyTuple>>,
kwargs: Option<&PyDict>,
) -> PyResult<PyObject> {
self.attach(py).as_any().call(args, kwargs).map(Into::into)
self.bind(py).as_any().call(args, kwargs).map(Into::into)
}
/// Calls the object with only positional arguments.
///
/// This is equivalent to the Python expression `self(*args)`.
pub fn call1(&self, py: Python<'_>, args: impl IntoPy<Py<PyTuple>>) -> PyResult<PyObject> {
self.attach(py).as_any().call1(args).map(Into::into)
self.bind(py).as_any().call1(args).map(Into::into)
}
/// Calls the object without arguments.
///
/// This is equivalent to the Python expression `self()`.
pub fn call0(&self, py: Python<'_>) -> PyResult<PyObject> {
self.attach(py).as_any().call0().map(Into::into)
self.bind(py).as_any().call0().map(Into::into)
}
/// Calls a method on the object.
@ -1035,7 +1036,7 @@ impl<T> Py<T> {
N: IntoPy<Py<PyString>>,
A: IntoPy<Py<PyTuple>>,
{
self.attach(py)
self.bind(py)
.as_any()
.call_method(name, args, kwargs)
.map(Into::into)
@ -1052,7 +1053,7 @@ impl<T> Py<T> {
N: IntoPy<Py<PyString>>,
A: IntoPy<Py<PyTuple>>,
{
self.attach(py)
self.bind(py)
.as_any()
.call_method1(name, args)
.map(Into::into)
@ -1068,7 +1069,7 @@ impl<T> Py<T> {
where
N: IntoPy<Py<PyString>>,
{
self.attach(py).as_any().call_method0(name).map(Into::into)
self.bind(py).as_any().call_method0(name).map(Into::into)
}
/// Create a `Py<T>` instance by taking ownership of the given FFI pointer.
@ -1624,7 +1625,7 @@ a = A()
#[test]
fn test_debug_fmt() {
Python::with_gil(|py| {
let obj = "hello world".to_object(py).attach_into(py);
let obj = "hello world".to_object(py).into_bound(py);
assert_eq!(format!("{:?}", obj), "'hello world'");
});
}
@ -1632,7 +1633,7 @@ a = A()
#[test]
fn test_display_fmt() {
Python::with_gil(|py| {
let obj = "hello world".to_object(py).attach_into(py);
let obj = "hello world".to_object(py).into_bound(py);
assert_eq!(format!("{}", obj), "hello world");
});
}

View File

@ -1728,7 +1728,7 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
}
let py = self.py();
inner(self, attr_name.into_py(self.py()).attach_into(py))
inner(self, attr_name.into_py(self.py()).into_bound(py))
}
fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
@ -1749,8 +1749,8 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
let py = self.py();
inner(
self,
attr_name.into_py(py).attach_into(py),
value.to_object(py).attach_into(py),
attr_name.into_py(py).into_bound(py),
value.to_object(py).into_bound(py),
)
}
@ -1765,7 +1765,7 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
}
let py = self.py();
inner(self, attr_name.into_py(py).attach_into(py))
inner(self, attr_name.into_py(py).into_bound(py))
}
fn compare<O>(&self, other: O) -> PyResult<Ordering>
@ -1795,7 +1795,7 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
}
let py = self.py();
inner(self, other.to_object(py).attach_into(py))
inner(self, other.to_object(py).into_bound(py))
}
fn rich_compare<O>(&self, other: O, compare_op: CompareOp) -> PyResult<Bound<'py, PyAny>>
@ -1814,7 +1814,7 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
}
let py = self.py();
inner(self, other.to_object(py).attach_into(py), compare_op)
inner(self, other.to_object(py).into_bound(py), compare_op)
}
fn lt<O>(&self, other: O) -> PyResult<bool>
@ -1890,7 +1890,7 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
}
let py = self.py();
inner(self, args.into_py(py).attach_into(py), kwargs)
inner(self, args.into_py(py).into_bound(py), kwargs)
}
fn call0(&self) -> PyResult<Bound<'py, PyAny>> {
@ -1937,7 +1937,7 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
// Optimized path on python 3.9+
unsafe {
let name = name.into_py(py).attach_into(py);
let name = name.into_py(py).into_bound(py);
ffi::PyObject_CallMethodNoArgs(self.as_ptr(), name.as_ptr()).assume_owned_or_err(py)
}
} else {
@ -1987,7 +1987,7 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
}
let py = self.py();
inner(self, key.to_object(py).attach_into(py))
inner(self, key.to_object(py).into_bound(py))
}
fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
@ -2008,8 +2008,8 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
let py = self.py();
inner(
self,
key.to_object(py).attach_into(py),
value.to_object(py).attach_into(py),
key.to_object(py).into_bound(py),
value.to_object(py).into_bound(py),
)
}
@ -2024,7 +2024,7 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
}
let py = self.py();
inner(self, key.to_object(py).attach_into(py))
inner(self, key.to_object(py).into_bound(py))
}
fn iter(&self) -> PyResult<Bound<'py, PyIterator>> {
@ -2184,7 +2184,7 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
}
let py = self.py();
inner(self, value.to_object(py).attach_into(py))
inner(self, value.to_object(py).into_bound(py))
}
#[cfg(not(PyPy))]

View File

@ -129,7 +129,7 @@ impl Py<PyBytes> {
/// immutable, the result may be used for as long as the reference to
/// `self` is held, including when the GIL is released.
pub fn as_bytes<'a>(&'a self, py: Python<'_>) -> &'a [u8] {
self.attach_borrow(py).as_bytes()
self.bind_borrowed(py).as_bytes()
}
}

View File

@ -391,7 +391,7 @@ impl<'py> PyDictMethods<'py> for Bound<'py, PyDict> {
}
let py = self.py();
inner(self, key.to_object(py).attach_into(py))
inner(self, key.to_object(py).into_bound(py))
}
fn get_item<K>(&self, key: K) -> PyResult<Option<Bound<'py, PyAny>>>
@ -414,7 +414,7 @@ impl<'py> PyDictMethods<'py> for Bound<'py, PyDict> {
}
let py = self.py();
inner(self, key.to_object(py).attach_into(py))
inner(self, key.to_object(py).into_bound(py))
}
fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
@ -435,8 +435,8 @@ impl<'py> PyDictMethods<'py> for Bound<'py, PyDict> {
let py = self.py();
inner(
self,
key.to_object(py).attach_into(py),
value.to_object(py).attach_into(py),
key.to_object(py).into_bound(py),
value.to_object(py).into_bound(py),
)
}
@ -451,7 +451,7 @@ impl<'py> PyDictMethods<'py> for Bound<'py, PyDict> {
}
let py = self.py();
inner(self, key.to_object(py).attach_into(py))
inner(self, key.to_object(py).into_bound(py))
}
fn keys(&self) -> Bound<'py, PyList> {

View File

@ -437,7 +437,7 @@ impl<'py> PyListMethods<'py> for Bound<'py, PyList> {
}
let py = self.py();
inner(self, index, item.to_object(py).attach_into(py))
inner(self, index, item.to_object(py).into_bound(py))
}
/// Deletes the `index`th element of self.
@ -483,7 +483,7 @@ impl<'py> PyListMethods<'py> for Bound<'py, PyList> {
}
let py = self.py();
inner(self, item.to_object(py).attach_into(py))
inner(self, item.to_object(py).into_bound(py))
}
/// Inserts an item at the specified index.
@ -500,7 +500,7 @@ impl<'py> PyListMethods<'py> for Bound<'py, PyList> {
}
let py = self.py();
inner(self, index, item.to_object(py).attach_into(py))
inner(self, index, item.to_object(py).into_bound(py))
}
/// Determines if self contains `value`.

View File

@ -375,7 +375,7 @@ impl<'py> PySequenceMethods<'py> for Bound<'py, PySequence> {
}
let py = self.py();
inner(self, i, item.to_object(py).attach_into(py))
inner(self, i, item.to_object(py).into_bound(py))
}
#[inline]
@ -417,7 +417,7 @@ impl<'py> PySequenceMethods<'py> for Bound<'py, PySequence> {
}
let py = self.py();
inner(self, value.to_object(py).attach_into(py))
inner(self, value.to_object(py).into_bound(py))
}
#[inline]
@ -435,7 +435,7 @@ impl<'py> PySequenceMethods<'py> for Bound<'py, PySequence> {
}
let py = self.py();
inner(self, value.to_object(py).attach_into(py))
inner(self, value.to_object(py).into_bound(py))
}
#[inline]
@ -450,7 +450,7 @@ impl<'py> PySequenceMethods<'py> for Bound<'py, PySequence> {
}
let py = self.py();
inner(self, value.to_object(self.py()).attach_into(py))
inner(self, value.to_object(self.py()).into_bound(py))
}
#[inline]

View File

@ -407,7 +407,7 @@ impl Py<PyString> {
/// the GIL lifetime.
#[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
pub fn to_str<'a>(&'a self, py: Python<'_>) -> PyResult<&'a str> {
self.attach_borrow(py).to_str()
self.bind_borrowed(py).to_str()
}
/// Converts the `PyString` into a Rust string, avoiding copying when possible.
@ -418,7 +418,7 @@ impl Py<PyString> {
/// Because `str` objects are immutable, the returned slice is independent of
/// the GIL lifetime.
pub fn to_cow<'a>(&'a self, py: Python<'_>) -> PyResult<Cow<'a, str>> {
self.attach_borrow(py).to_cow()
self.bind_borrowed(py).to_cow()
}
/// Converts the `PyString` into a Rust string.
@ -429,7 +429,7 @@ impl Py<PyString> {
/// Because `str` objects are immutable, the returned slice is independent of
/// the GIL lifetime.
pub fn to_string_lossy<'a>(&'a self, py: Python<'_>) -> Cow<'a, str> {
self.attach_borrow(py).to_string_lossy()
self.bind_borrowed(py).to_string_lossy()
}
}