Skip to content

Commit

Permalink
Correction
Browse files Browse the repository at this point in the history
  • Loading branch information
moriyoshi committed Jun 19, 2021
1 parent b7ef080 commit b9f28dc
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 14 deletions.
6 changes: 0 additions & 6 deletions src/ffi/abstract_.rs
Expand Up @@ -3,12 +3,6 @@ use crate::ffi::pyport::Py_ssize_t;
use std::os::raw::{c_char, c_int};
use std::ptr;

#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
#[cfg_attr(PyPy, link_name = "PyPySequence_Type")]
pub static mut PySequence_Type: PyTypeObject;
}

extern "C" {
#[cfg(PyPy)]
#[link_name = "PyPyObject_DelAttrString"]
Expand Down
28 changes: 27 additions & 1 deletion src/instance.rs
Expand Up @@ -3,7 +3,7 @@ use crate::conversion::{PyTryFrom, ToBorrowedObject};
use crate::err::{PyDowncastError, PyErr, PyResult};
use crate::gil;
use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell};
use crate::types::{PyDict, PyTuple};
use crate::types::{PyDict, PyTuple, PySequence};
use crate::{
ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyClass, PyClassInitializer,
PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject,
Expand Down Expand Up @@ -128,6 +128,32 @@ where
}
}

impl Py<PySequence> {
/// Borrows a GIL-bound reference to the PySequence. By binding to the GIL lifetime, this
/// allows the GIL-bound reference to not require `Python` for any of its methods.
///
/// ```
/// # use pyo3::prelude::*;
/// # use pyo3::types::PyList;
/// # Python::with_gil(|py| {
/// let list: Py<PyList> = PyList::empty(py).cast_as::<PySequence>().unwrap().into();
/// let seq: &PySequence = list.as_ref(py);
/// assert_eq!(seq.len().unwrap(), 0);
/// # });
/// ```
pub fn as_ref<'py>(&'py self, _py: Python<'py>) -> &'py PySequence {
let any = self.as_ptr() as *const PyAny;
unsafe { PyNativeType::unchecked_downcast(&*any) }
}

/// Similar to [`as_ref`](#method.as_ref), and also consumes this `Py` and registers the
/// Python object reference in PyO3's object storage. The reference count for the Python
/// object will not be decreased until the GIL lifetime ends.
pub fn into_ref(self, py: Python) -> &PySequence {
unsafe { py.from_owned_ptr(self.into_ptr()) }
}
}

impl<T> Py<T>
where
T: PyClass,
Expand Down
37 changes: 30 additions & 7 deletions src/types/sequence.rs
@@ -1,6 +1,6 @@
// Copyright (c) 2017-present PyO3 Project and Contributors

use crate::err::{self, PyErr, PyResult};
use crate::err::{self, PyDowncastError, PyErr, PyResult};
use crate::ffi::{self, Py_ssize_t};
use crate::instance::PyNativeType;
use crate::types::{PyAny, PyList, PyTuple};
Expand All @@ -11,7 +11,6 @@ use crate::{FromPyObject, PyTryFrom, ToBorrowedObject};
#[repr(transparent)]
pub struct PySequence(PyAny);
pyobject_native_type_named!(PySequence);
pyobject_native_type_info!(PySequence, ffi::PySequence_Type, Some("builtins"), #checkfunction=ffi::PySequence_Check);
pyobject_native_type_extract!(PySequence);

impl PySequence {
Expand Down Expand Up @@ -294,6 +293,29 @@ where
}
}

impl<'v> PyTryFrom<'v> for PySequence {
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PySequence, PyDowncastError<'v>> {
let value = value.into();
unsafe {
if ffi::PySequence_Check(value.as_ptr()) != 0 {
Ok(<PySequence as PyTryFrom>::try_from_unchecked(value))
} else {
Err(PyDowncastError::new(value, "Sequence"))
}
}
}

fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v PySequence, PyDowncastError<'v>> {
<PySequence as PyTryFrom>::try_from(value)
}

#[inline]
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v PySequence {
let ptr = value.into() as *const _ as *const PySequence;
&*ptr
}
}

fn extract_sequence<'s, T>(obj: &'s PyAny) -> PyResult<Vec<T>>
where
T: FromPyObject<'s>,
Expand All @@ -312,6 +334,7 @@ mod test {
use crate::AsPyPointer;
use crate::Python;
use crate::{Py, PyObject, PyTryFrom, ToPyObject};
use crate::types::PyList;

fn get_object() -> PyObject {
// Convenience function for getting a single unique object
Expand Down Expand Up @@ -641,7 +664,7 @@ mod test {
}

#[test]
fn test_as_empty() {
fn test_is_empty() {
let gil = Python::acquire_gil();
let py = gil.python();
let list = vec![1].to_object(py);
Expand All @@ -654,11 +677,11 @@ mod test {
}

#[test]
fn test_is_ref() {
fn test_as_ref() {
let gil = Python::acquire_gil();
let py = gil.python();
let list = vec!["foo"].to_object(py);
let seq: Py<PySequence> = list.cast_as::<PySequence>(py).unwrap().into();
assert!(seq.as_ref(py).extract::<Vec<&str>>().unwrap() == ["foo"]);
let seq: Py<PySequence> = PyList::empty(py).cast_as::<PySequence>().unwrap().into();
let seq_ref: &PySequence = seq.as_ref(py);
assert_eq!(seq_ref.len().unwrap(), 0);
}
}

0 comments on commit b9f28dc

Please sign in to comment.