Skip to content

Commit

Permalink
Add Py::bind, Py::into_bound, and Py::bind_borrowed
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt committed Dec 21, 2023
1 parent 63b1c2c commit db3b345
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 44 deletions.
31 changes: 16 additions & 15 deletions src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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.
Expand Down Expand Up @@ -1624,15 +1625,15 @@ 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'");
});
}

#[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");
});
}
Expand Down
26 changes: 13 additions & 13 deletions src/types/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<()>
Expand All @@ -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),
)
}

Expand All @@ -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>
Expand Down Expand Up @@ -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>>
Expand All @@ -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>
Expand Down Expand Up @@ -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>> {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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<()>
Expand All @@ -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),
)
}

Expand All @@ -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>> {
Expand Down Expand Up @@ -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))]
Expand Down
2 changes: 1 addition & 1 deletion src/types/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/types/dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>>
Expand All @@ -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<()>
Expand All @@ -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),
)
}

Expand All @@ -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> {
Expand Down
6 changes: 3 additions & 3 deletions src/types/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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`.
Expand Down
8 changes: 4 additions & 4 deletions src/types/sequence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand All @@ -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]
Expand All @@ -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]
Expand Down
6 changes: 3 additions & 3 deletions src/types/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -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()
}
}

Expand Down

0 comments on commit db3b345

Please sign in to comment.