diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0f8d0a1..4db89a41 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ jobs: with: toolchain: 1.56.0 targets: x86_64-unknown-linux-gnu - components: clippy,rust-src + components: rust-src - uses: actions/setup-python@v4 with: architecture: "x64" diff --git a/Cargo.toml b/Cargo.toml index 0bc281ea..651d4157 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,9 +48,7 @@ chrono = { version = "0.4" } criterion = "0.3.5" # Required for "and $N others" normalization trybuild = ">=1.0.70" -rustversion = "1.0" -# 1.0.0 requires Rust 1.50 -proptest = { version = "0.10.1", default-features = false, features = ["std"] } +proptest = { version = "1.0", default-features = false, features = ["std"] } send_wrapper = "0.6" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.61" diff --git a/build.rs b/build.rs index 78cebf9a..207f122c 100644 --- a/build.rs +++ b/build.rs @@ -46,7 +46,7 @@ fn configure_pyo3() -> Result<()> { ensure_auto_initialize_ok(interpreter_config)?; - // Emit cfgs like `addr_of` and `min_const_generics` + // Emit cfgs like `thread_local_const_init` print_feature_cfgs(); Ok(()) diff --git a/noxfile.py b/noxfile.py index 7b8246e1..c30c687a 100644 --- a/noxfile.py +++ b/noxfile.py @@ -435,6 +435,7 @@ def set_minimal_package_versions(session: nox.Session): "rayon": "1.6.1", "rayon-core": "1.10.2", "regex": "1.7.3", + "proptest": "1.0.0", } # run cargo update first to ensure that everything is at highest diff --git a/pyo3-build-config/src/lib.rs b/pyo3-build-config/src/lib.rs index 07c5bcb6..05320add 100644 --- a/pyo3-build-config/src/lib.rs +++ b/pyo3-build-config/src/lib.rs @@ -142,30 +142,10 @@ pub fn print_feature_cfgs() { let rustc_minor_version = rustc_minor_version().unwrap_or(0); - // Enable use of const generics on Rust 1.51 and greater - if rustc_minor_version >= 51 { - println!("cargo:rustc-cfg=min_const_generics"); - } - - // Enable use of std::ptr::addr_of! on Rust 1.51 and greater - if rustc_minor_version >= 51 { - println!("cargo:rustc-cfg=addr_of"); - } - - // Enable use of Option::insert on Rust 1.53 and greater - if rustc_minor_version >= 53 { - println!("cargo:rustc-cfg=option_insert"); - } - // Enable use of const initializer for thread_local! on Rust 1.59 and greater if rustc_minor_version >= 59 { println!("cargo:rustc-cfg=thread_local_const_init"); } - - // Enable use of `#[cfg(panic = "...")]` on Rust 1.60 and greater - if rustc_minor_version >= 60 { - println!("cargo:rustc-cfg=panic_unwind"); - } } /// Private exports used in PyO3's build.rs diff --git a/pyo3-ffi/build.rs b/pyo3-ffi/build.rs index 1dd37820..c472003d 100644 --- a/pyo3-ffi/build.rs +++ b/pyo3-ffi/build.rs @@ -100,7 +100,7 @@ fn configure_pyo3() -> Result<()> { println!("{}", line); } - // Emit cfgs like `addr_of` and `min_const_generics` + // Emit cfgs like `thread_local_const_init` print_feature_cfgs(); Ok(()) diff --git a/pyo3-ffi/src/boolobject.rs b/pyo3-ffi/src/boolobject.rs index 17af974b..81e1308e 100644 --- a/pyo3-ffi/src/boolobject.rs +++ b/pyo3-ffi/src/boolobject.rs @@ -1,6 +1,7 @@ use crate::longobject::PyLongObject; use crate::object::*; use std::os::raw::{c_int, c_long}; +use std::ptr::addr_of_mut; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { @@ -10,7 +11,7 @@ extern "C" { #[inline] pub unsafe fn PyBool_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyBool_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyBool_Type)) as c_int } #[cfg_attr(windows, link(name = "pythonXY"))] @@ -23,12 +24,12 @@ extern "C" { #[inline] pub unsafe fn Py_False() -> *mut PyObject { - addr_of_mut_shim!(_Py_FalseStruct) as *mut PyLongObject as *mut PyObject + addr_of_mut!(_Py_FalseStruct) as *mut PyLongObject as *mut PyObject } #[inline] pub unsafe fn Py_True() -> *mut PyObject { - addr_of_mut_shim!(_Py_TrueStruct) as *mut PyLongObject as *mut PyObject + addr_of_mut!(_Py_TrueStruct) as *mut PyLongObject as *mut PyObject } #[inline] diff --git a/pyo3-ffi/src/bytearrayobject.rs b/pyo3-ffi/src/bytearrayobject.rs index 93780e73..a37deb41 100644 --- a/pyo3-ffi/src/bytearrayobject.rs +++ b/pyo3-ffi/src/bytearrayobject.rs @@ -1,6 +1,7 @@ use crate::object::*; use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; +use std::ptr::addr_of_mut; #[cfg(not(any(PyPy, Py_LIMITED_API)))] #[repr(C)] @@ -29,12 +30,12 @@ extern "C" { #[inline] pub unsafe fn PyByteArray_Check(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, addr_of_mut_shim!(PyByteArray_Type)) + PyObject_TypeCheck(op, addr_of_mut!(PyByteArray_Type)) } #[inline] pub unsafe fn PyByteArray_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyByteArray_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyByteArray_Type)) as c_int } extern "C" { diff --git a/pyo3-ffi/src/bytesobject.rs b/pyo3-ffi/src/bytesobject.rs index 8cdcd7df..0fd327b6 100644 --- a/pyo3-ffi/src/bytesobject.rs +++ b/pyo3-ffi/src/bytesobject.rs @@ -1,6 +1,7 @@ use crate::object::*; use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; +use std::ptr::addr_of_mut; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { @@ -16,7 +17,7 @@ pub unsafe fn PyBytes_Check(op: *mut PyObject) -> c_int { #[inline] pub unsafe fn PyBytes_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyBytes_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyBytes_Type)) as c_int } extern "C" { diff --git a/pyo3-ffi/src/complexobject.rs b/pyo3-ffi/src/complexobject.rs index 83b7620a..339f5d8c 100644 --- a/pyo3-ffi/src/complexobject.rs +++ b/pyo3-ffi/src/complexobject.rs @@ -1,5 +1,6 @@ use crate::object::*; use std::os::raw::{c_double, c_int}; +use std::ptr::addr_of_mut; #[repr(C)] #[derive(Copy, Clone)] @@ -40,12 +41,12 @@ extern "C" { #[inline] pub unsafe fn PyComplex_Check(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, addr_of_mut_shim!(PyComplex_Type)) + PyObject_TypeCheck(op, addr_of_mut!(PyComplex_Type)) } #[inline] pub unsafe fn PyComplex_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyComplex_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyComplex_Type)) as c_int } extern "C" { diff --git a/pyo3-ffi/src/context.rs b/pyo3-ffi/src/context.rs index a4ee09e3..210d6e21 100644 --- a/pyo3-ffi/src/context.rs +++ b/pyo3-ffi/src/context.rs @@ -1,5 +1,6 @@ use crate::object::{PyObject, PyTypeObject, Py_TYPE}; use std::os::raw::{c_char, c_int}; +use std::ptr::addr_of_mut; extern "C" { pub static mut PyContext_Type: PyTypeObject; @@ -12,17 +13,17 @@ extern "C" { #[inline] pub unsafe fn PyContext_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyContext_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyContext_Type)) as c_int } #[inline] pub unsafe fn PyContextVar_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyContextVar_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyContextVar_Type)) as c_int } #[inline] pub unsafe fn PyContextToken_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyContextToken_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyContextToken_Type)) as c_int } extern "C" { diff --git a/pyo3-ffi/src/cpython/code.rs b/pyo3-ffi/src/cpython/code.rs index b77b2f98..995771dc 100644 --- a/pyo3-ffi/src/cpython/code.rs +++ b/pyo3-ffi/src/cpython/code.rs @@ -3,6 +3,8 @@ use crate::pyport::Py_ssize_t; #[allow(unused_imports)] use std::os::raw::{c_char, c_int, c_uchar, c_void}; +#[cfg(not(PyPy))] +use std::ptr::addr_of_mut; // skipped _Py_CODEUNIT // skipped _Py_OPCODE @@ -159,7 +161,7 @@ extern "C" { #[inline] #[cfg(not(PyPy))] pub unsafe fn PyCode_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyCode_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyCode_Type)) as c_int } #[inline] diff --git a/pyo3-ffi/src/cpython/frameobject.rs b/pyo3-ffi/src/cpython/frameobject.rs index cd8fc75a..7410000e 100644 --- a/pyo3-ffi/src/cpython/frameobject.rs +++ b/pyo3-ffi/src/cpython/frameobject.rs @@ -4,6 +4,7 @@ use crate::pystate::PyThreadState; #[cfg(not(any(PyPy, Py_3_11)))] use std::os::raw::c_char; use std::os::raw::c_int; +use std::ptr::addr_of_mut; #[cfg(not(any(PyPy, Py_3_11)))] pub type PyFrameState = c_char; @@ -64,7 +65,7 @@ extern "C" { #[inline] pub unsafe fn PyFrame_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyFrame_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyFrame_Type)) as c_int } extern "C" { diff --git a/pyo3-ffi/src/cpython/funcobject.rs b/pyo3-ffi/src/cpython/funcobject.rs index 443988dd..9a01e4c1 100644 --- a/pyo3-ffi/src/cpython/funcobject.rs +++ b/pyo3-ffi/src/cpython/funcobject.rs @@ -1,4 +1,6 @@ use std::os::raw::c_int; +#[cfg(not(all(PyPy, not(Py_3_8))))] +use std::ptr::addr_of_mut; use crate::PyObject; @@ -61,7 +63,7 @@ extern "C" { #[cfg(not(all(PyPy, not(Py_3_8))))] #[inline] pub unsafe fn PyFunction_Check(op: *mut PyObject) -> c_int { - (crate::Py_TYPE(op) == addr_of_mut_shim!(PyFunction_Type)) as c_int + (crate::Py_TYPE(op) == addr_of_mut!(PyFunction_Type)) as c_int } extern "C" { diff --git a/pyo3-ffi/src/cpython/genobject.rs b/pyo3-ffi/src/cpython/genobject.rs index 6b522bf8..bc0986a0 100644 --- a/pyo3-ffi/src/cpython/genobject.rs +++ b/pyo3-ffi/src/cpython/genobject.rs @@ -5,6 +5,7 @@ use crate::_PyErr_StackItem; #[cfg(Py_3_11)] use std::os::raw::c_char; use std::os::raw::c_int; +use std::ptr::addr_of_mut; #[cfg(not(PyPy))] #[repr(C)] @@ -41,12 +42,12 @@ extern "C" { #[inline] pub unsafe fn PyGen_Check(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, addr_of_mut_shim!(PyGen_Type)) + PyObject_TypeCheck(op, addr_of_mut!(PyGen_Type)) } #[inline] pub unsafe fn PyGen_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyGen_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyGen_Type)) as c_int } extern "C" { @@ -71,7 +72,7 @@ extern "C" { #[inline] pub unsafe fn PyCoro_CheckExact(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, addr_of_mut_shim!(PyCoro_Type)) + PyObject_TypeCheck(op, addr_of_mut!(PyCoro_Type)) } // skipped _PyCoro_GetAwaitableIter @@ -91,7 +92,7 @@ extern "C" { #[inline] pub unsafe fn PyAsyncGen_CheckExact(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, addr_of_mut_shim!(PyAsyncGen_Type)) + PyObject_TypeCheck(op, addr_of_mut!(PyAsyncGen_Type)) } // skipped _PyAsyncGenValueWrapperNew diff --git a/pyo3-ffi/src/cpython/methodobject.rs b/pyo3-ffi/src/cpython/methodobject.rs index 3dd0d898..7d965978 100644 --- a/pyo3-ffi/src/cpython/methodobject.rs +++ b/pyo3-ffi/src/cpython/methodobject.rs @@ -1,6 +1,7 @@ use crate::object::*; use crate::{PyCFunctionObject, PyMethodDefPointer, METH_METHOD, METH_STATIC}; use std::os::raw::c_int; +use std::ptr::addr_of_mut; pub struct PyCMethodObject { pub func: PyCFunctionObject, @@ -14,12 +15,12 @@ extern "C" { #[inline] pub unsafe fn PyCMethod_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyCMethod_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyCMethod_Type)) as c_int } #[inline] pub unsafe fn PyCMethod_Check(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, addr_of_mut_shim!(PyCMethod_Type)) + PyObject_TypeCheck(op, addr_of_mut!(PyCMethod_Type)) } #[inline] diff --git a/pyo3-ffi/src/dictobject.rs b/pyo3-ffi/src/dictobject.rs index b03fbb30..3215d882 100644 --- a/pyo3-ffi/src/dictobject.rs +++ b/pyo3-ffi/src/dictobject.rs @@ -1,6 +1,7 @@ use crate::object::*; use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; +use std::ptr::addr_of_mut; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { @@ -15,7 +16,7 @@ pub unsafe fn PyDict_Check(op: *mut PyObject) -> c_int { #[inline] pub unsafe fn PyDict_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyDict_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyDict_Type)) as c_int } extern "C" { @@ -76,17 +77,17 @@ extern "C" { #[inline] pub unsafe fn PyDictKeys_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyDictKeys_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyDictKeys_Type)) as c_int } #[inline] pub unsafe fn PyDictValues_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyDictValues_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyDictValues_Type)) as c_int } #[inline] pub unsafe fn PyDictItems_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyDictItems_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyDictItems_Type)) as c_int } #[inline] diff --git a/pyo3-ffi/src/floatobject.rs b/pyo3-ffi/src/floatobject.rs index 15f71ba2..176789d3 100644 --- a/pyo3-ffi/src/floatobject.rs +++ b/pyo3-ffi/src/floatobject.rs @@ -1,5 +1,6 @@ use crate::object::*; use std::os::raw::{c_double, c_int}; +use std::ptr::addr_of_mut; #[cfg(Py_LIMITED_API)] // TODO: remove (see https://github.com/PyO3/pyo3/pull/1341#issuecomment-751515985) @@ -20,12 +21,12 @@ extern "C" { #[inline] pub unsafe fn PyFloat_Check(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, addr_of_mut_shim!(PyFloat_Type)) + PyObject_TypeCheck(op, addr_of_mut!(PyFloat_Type)) } #[inline] pub unsafe fn PyFloat_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyFloat_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyFloat_Type)) as c_int } // skipped Py_RETURN_NAN diff --git a/pyo3-ffi/src/iterobject.rs b/pyo3-ffi/src/iterobject.rs index 657409c7..aa0c7b26 100644 --- a/pyo3-ffi/src/iterobject.rs +++ b/pyo3-ffi/src/iterobject.rs @@ -1,5 +1,6 @@ use crate::object::*; use std::os::raw::c_int; +use std::ptr::addr_of_mut; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { @@ -9,7 +10,7 @@ extern "C" { #[inline] pub unsafe fn PySeqIter_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PySeqIter_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PySeqIter_Type)) as c_int } extern "C" { @@ -19,7 +20,7 @@ extern "C" { #[inline] pub unsafe fn PyCallIter_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyCallIter_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyCallIter_Type)) as c_int } extern "C" { diff --git a/pyo3-ffi/src/lib.rs b/pyo3-ffi/src/lib.rs index fc938668..091daee4 100644 --- a/pyo3-ffi/src/lib.rs +++ b/pyo3-ffi/src/lib.rs @@ -258,19 +258,6 @@ macro_rules! opaque_struct { }; } -macro_rules! addr_of_mut_shim { - ($place:expr) => {{ - #[cfg(addr_of)] - { - ::std::ptr::addr_of_mut!($place) - } - #[cfg(not(addr_of))] - { - &mut $place as *mut _ - } - }}; -} - pub use self::abstract_::*; pub use self::bltinmodule::*; pub use self::boolobject::*; diff --git a/pyo3-ffi/src/listobject.rs b/pyo3-ffi/src/listobject.rs index 9b10a917..32c6a2dc 100644 --- a/pyo3-ffi/src/listobject.rs +++ b/pyo3-ffi/src/listobject.rs @@ -1,6 +1,7 @@ use crate::object::*; use crate::pyport::Py_ssize_t; use std::os::raw::c_int; +use std::ptr::addr_of_mut; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { @@ -17,7 +18,7 @@ pub unsafe fn PyList_Check(op: *mut PyObject) -> c_int { #[inline] pub unsafe fn PyList_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyList_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyList_Type)) as c_int } extern "C" { diff --git a/pyo3-ffi/src/longobject.rs b/pyo3-ffi/src/longobject.rs index 72e42b3d..55ea8fa1 100644 --- a/pyo3-ffi/src/longobject.rs +++ b/pyo3-ffi/src/longobject.rs @@ -4,6 +4,7 @@ use libc::size_t; #[cfg(not(Py_LIMITED_API))] use std::os::raw::c_uchar; use std::os::raw::{c_char, c_double, c_int, c_long, c_longlong, c_ulong, c_ulonglong, c_void}; +use std::ptr::addr_of_mut; opaque_struct!(PyLongObject); @@ -20,7 +21,7 @@ pub unsafe fn PyLong_Check(op: *mut PyObject) -> c_int { #[inline] pub unsafe fn PyLong_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyLong_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyLong_Type)) as c_int } extern "C" { diff --git a/pyo3-ffi/src/memoryobject.rs b/pyo3-ffi/src/memoryobject.rs index 333529d0..fe68ee8d 100644 --- a/pyo3-ffi/src/memoryobject.rs +++ b/pyo3-ffi/src/memoryobject.rs @@ -1,6 +1,7 @@ use crate::object::*; use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; +use std::ptr::addr_of_mut; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { @@ -13,7 +14,7 @@ extern "C" { #[inline] pub unsafe fn PyMemoryView_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyMemoryView_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyMemoryView_Type)) as c_int } // skipped non-limited PyMemoryView_GET_BUFFER diff --git a/pyo3-ffi/src/methodobject.rs b/pyo3-ffi/src/methodobject.rs index 5c378871..5b50d2fc 100644 --- a/pyo3-ffi/src/methodobject.rs +++ b/pyo3-ffi/src/methodobject.rs @@ -24,19 +24,19 @@ extern "C" { #[cfg(Py_3_9)] #[inline] pub unsafe fn PyCFunction_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyCFunction_Type)) as c_int + (Py_TYPE(op) == ptr::addr_of_mut!(PyCFunction_Type)) as c_int } #[cfg(Py_3_9)] #[inline] pub unsafe fn PyCFunction_Check(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, addr_of_mut_shim!(PyCFunction_Type)) + PyObject_TypeCheck(op, ptr::addr_of_mut!(PyCFunction_Type)) } #[cfg(not(Py_3_9))] #[inline] pub unsafe fn PyCFunction_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyCFunction_Type)) as c_int + (Py_TYPE(op) == ptr::addr_of_mut!(PyCFunction_Type)) as c_int } pub type PyCFunction = diff --git a/pyo3-ffi/src/moduleobject.rs b/pyo3-ffi/src/moduleobject.rs index f7873060..72482498 100644 --- a/pyo3-ffi/src/moduleobject.rs +++ b/pyo3-ffi/src/moduleobject.rs @@ -2,6 +2,7 @@ use crate::methodobject::PyMethodDef; use crate::object::*; use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int, c_void}; +use std::ptr::addr_of_mut; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { @@ -11,12 +12,12 @@ extern "C" { #[inline] pub unsafe fn PyModule_Check(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, addr_of_mut_shim!(PyModule_Type)) + PyObject_TypeCheck(op, addr_of_mut!(PyModule_Type)) } #[inline] pub unsafe fn PyModule_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyModule_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyModule_Type)) as c_int } extern "C" { diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 7fabcdf6..b61548de 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -488,7 +488,7 @@ extern "C" { #[inline] pub unsafe fn Py_None() -> *mut PyObject { - addr_of_mut_shim!(_Py_NoneStruct) + ptr::addr_of_mut!(_Py_NoneStruct) } #[inline] @@ -506,7 +506,7 @@ extern "C" { #[inline] pub unsafe fn Py_NotImplemented() -> *mut PyObject { - addr_of_mut_shim!(_Py_NotImplementedStruct) + ptr::addr_of_mut!(_Py_NotImplementedStruct) } // skipped Py_RETURN_NOTIMPLEMENTED @@ -554,5 +554,5 @@ pub unsafe fn PyType_Check(op: *mut PyObject) -> c_int { #[inline] pub unsafe fn PyType_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyType_Type)) as c_int + (Py_TYPE(op) == ptr::addr_of_mut!(PyType_Type)) as c_int } diff --git a/pyo3-ffi/src/pycapsule.rs b/pyo3-ffi/src/pycapsule.rs index 382d7eb8..5b77841c 100644 --- a/pyo3-ffi/src/pycapsule.rs +++ b/pyo3-ffi/src/pycapsule.rs @@ -1,5 +1,6 @@ use crate::object::*; use std::os::raw::{c_char, c_int, c_void}; +use std::ptr::addr_of_mut; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { @@ -11,7 +12,7 @@ pub type PyCapsule_Destructor = unsafe extern "C" fn(o: *mut PyObject); #[inline] pub unsafe fn PyCapsule_CheckExact(ob: *mut PyObject) -> c_int { - (Py_TYPE(ob) == addr_of_mut_shim!(PyCapsule_Type)) as c_int + (Py_TYPE(ob) == addr_of_mut!(PyCapsule_Type)) as c_int } extern "C" { diff --git a/pyo3-ffi/src/rangeobject.rs b/pyo3-ffi/src/rangeobject.rs index be617377..408b5cdc 100644 --- a/pyo3-ffi/src/rangeobject.rs +++ b/pyo3-ffi/src/rangeobject.rs @@ -1,5 +1,6 @@ use crate::object::*; use std::os::raw::c_int; +use std::ptr::addr_of_mut; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { @@ -11,5 +12,5 @@ extern "C" { #[inline] pub unsafe fn PyRange_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyRange_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyRange_Type)) as c_int } diff --git a/pyo3-ffi/src/setobject.rs b/pyo3-ffi/src/setobject.rs index 5c7345aa..84a368a7 100644 --- a/pyo3-ffi/src/setobject.rs +++ b/pyo3-ffi/src/setobject.rs @@ -3,6 +3,7 @@ use crate::object::*; use crate::pyport::Py_hash_t; use crate::pyport::Py_ssize_t; use std::os::raw::c_int; +use std::ptr::addr_of_mut; pub const PySet_MINSIZE: usize = 8; @@ -93,7 +94,7 @@ extern "C" { #[inline] #[cfg(not(PyPy))] pub unsafe fn PyFrozenSet_CheckExact(ob: *mut PyObject) -> c_int { - (Py_TYPE(ob) == addr_of_mut_shim!(PyFrozenSet_Type)) as c_int + (Py_TYPE(ob) == addr_of_mut!(PyFrozenSet_Type)) as c_int } extern "C" { @@ -105,8 +106,8 @@ extern "C" { #[inline] #[cfg(not(PyPy))] pub unsafe fn PyFrozenSet_Check(ob: *mut PyObject) -> c_int { - (Py_TYPE(ob) == addr_of_mut_shim!(PyFrozenSet_Type) - || PyType_IsSubtype(Py_TYPE(ob), addr_of_mut_shim!(PyFrozenSet_Type)) != 0) as c_int + (Py_TYPE(ob) == addr_of_mut!(PyFrozenSet_Type) + || PyType_IsSubtype(Py_TYPE(ob), addr_of_mut!(PyFrozenSet_Type)) != 0) as c_int } extern "C" { @@ -118,21 +119,21 @@ extern "C" { #[inline] #[cfg(not(PyPy))] pub unsafe fn PyAnySet_CheckExact(ob: *mut PyObject) -> c_int { - (Py_TYPE(ob) == addr_of_mut_shim!(PySet_Type) - || Py_TYPE(ob) == addr_of_mut_shim!(PyFrozenSet_Type)) as c_int + (Py_TYPE(ob) == addr_of_mut!(PySet_Type) || Py_TYPE(ob) == addr_of_mut!(PyFrozenSet_Type)) + as c_int } #[inline] pub unsafe fn PyAnySet_Check(ob: *mut PyObject) -> c_int { (PyAnySet_CheckExact(ob) != 0 - || PyType_IsSubtype(Py_TYPE(ob), addr_of_mut_shim!(PySet_Type)) != 0 - || PyType_IsSubtype(Py_TYPE(ob), addr_of_mut_shim!(PyFrozenSet_Type)) != 0) as c_int + || PyType_IsSubtype(Py_TYPE(ob), addr_of_mut!(PySet_Type)) != 0 + || PyType_IsSubtype(Py_TYPE(ob), addr_of_mut!(PyFrozenSet_Type)) != 0) as c_int } #[inline] #[cfg(Py_3_10)] pub unsafe fn PySet_CheckExact(op: *mut PyObject) -> c_int { - crate::Py_IS_TYPE(op, addr_of_mut_shim!(PySet_Type)) + crate::Py_IS_TYPE(op, addr_of_mut!(PySet_Type)) } extern "C" { @@ -144,6 +145,6 @@ extern "C" { #[inline] #[cfg(not(PyPy))] pub unsafe fn PySet_Check(ob: *mut PyObject) -> c_int { - (Py_TYPE(ob) == addr_of_mut_shim!(PySet_Type) - || PyType_IsSubtype(Py_TYPE(ob), addr_of_mut_shim!(PySet_Type)) != 0) as c_int + (Py_TYPE(ob) == addr_of_mut!(PySet_Type) + || PyType_IsSubtype(Py_TYPE(ob), addr_of_mut!(PySet_Type)) != 0) as c_int } diff --git a/pyo3-ffi/src/sliceobject.rs b/pyo3-ffi/src/sliceobject.rs index 1dbd14fb..6f09906f 100644 --- a/pyo3-ffi/src/sliceobject.rs +++ b/pyo3-ffi/src/sliceobject.rs @@ -1,6 +1,7 @@ use crate::object::*; use crate::pyport::Py_ssize_t; use std::os::raw::c_int; +use std::ptr::addr_of_mut; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { @@ -10,7 +11,7 @@ extern "C" { #[inline] pub unsafe fn Py_Ellipsis() -> *mut PyObject { - addr_of_mut_shim!(_Py_EllipsisObject) + addr_of_mut!(_Py_EllipsisObject) } #[cfg(not(Py_LIMITED_API))] @@ -31,7 +32,7 @@ extern "C" { #[inline] pub unsafe fn PySlice_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PySlice_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PySlice_Type)) as c_int } extern "C" { diff --git a/pyo3-ffi/src/traceback.rs b/pyo3-ffi/src/traceback.rs index b3a25844..432b6980 100644 --- a/pyo3-ffi/src/traceback.rs +++ b/pyo3-ffi/src/traceback.rs @@ -1,5 +1,7 @@ use crate::object::*; use std::os::raw::c_int; +#[cfg(not(PyPy))] +use std::ptr::addr_of_mut; extern "C" { #[cfg_attr(PyPy, link_name = "PyPyTraceBack_Here")] @@ -21,5 +23,5 @@ extern "C" { #[inline] #[cfg(not(PyPy))] pub unsafe fn PyTraceBack_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyTraceBack_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyTraceBack_Type)) as c_int } diff --git a/pyo3-ffi/src/tupleobject.rs b/pyo3-ffi/src/tupleobject.rs index de3c4c54..d265c91a 100644 --- a/pyo3-ffi/src/tupleobject.rs +++ b/pyo3-ffi/src/tupleobject.rs @@ -1,6 +1,7 @@ use crate::object::*; use crate::pyport::Py_ssize_t; use std::os::raw::c_int; +use std::ptr::addr_of_mut; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { @@ -16,7 +17,7 @@ pub unsafe fn PyTuple_Check(op: *mut PyObject) -> c_int { #[inline] pub unsafe fn PyTuple_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyTuple_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyTuple_Type)) as c_int } extern "C" { diff --git a/pyo3-ffi/src/unicodeobject.rs b/pyo3-ffi/src/unicodeobject.rs index 86075475..d7cdc399 100644 --- a/pyo3-ffi/src/unicodeobject.rs +++ b/pyo3-ffi/src/unicodeobject.rs @@ -2,6 +2,8 @@ use crate::object::*; use crate::pyport::Py_ssize_t; use libc::wchar_t; use std::os::raw::{c_char, c_int, c_void}; +#[cfg(not(PyPy))] +use std::ptr::addr_of_mut; #[cfg(not(Py_LIMITED_API))] pub type Py_UNICODE = wchar_t; @@ -34,7 +36,7 @@ pub unsafe fn PyUnicode_Check(op: *mut PyObject) -> c_int { #[inline] #[cfg(not(PyPy))] pub unsafe fn PyUnicode_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(PyUnicode_Type)) as c_int + (Py_TYPE(op) == addr_of_mut!(PyUnicode_Type)) as c_int } pub const Py_UNICODE_REPLACEMENT_CHARACTER: Py_UCS4 = 0xFFFD; diff --git a/pyo3-ffi/src/weakrefobject.rs b/pyo3-ffi/src/weakrefobject.rs index 9c063b0e..d065ae23 100644 --- a/pyo3-ffi/src/weakrefobject.rs +++ b/pyo3-ffi/src/weakrefobject.rs @@ -1,5 +1,7 @@ use crate::object::*; use std::os::raw::c_int; +#[cfg(not(PyPy))] +use std::ptr::addr_of_mut; #[cfg(all(not(PyPy), Py_LIMITED_API))] opaque_struct!(PyWeakReference); @@ -29,20 +31,20 @@ extern "C" { #[inline] #[cfg(not(PyPy))] pub unsafe fn PyWeakref_CheckRef(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, addr_of_mut_shim!(_PyWeakref_RefType)) + PyObject_TypeCheck(op, addr_of_mut!(_PyWeakref_RefType)) } #[inline] #[cfg(not(PyPy))] pub unsafe fn PyWeakref_CheckRefExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == addr_of_mut_shim!(_PyWeakref_RefType)) as c_int + (Py_TYPE(op) == addr_of_mut!(_PyWeakref_RefType)) as c_int } #[inline] #[cfg(not(PyPy))] pub unsafe fn PyWeakref_CheckProxy(op: *mut PyObject) -> c_int { - ((Py_TYPE(op) == addr_of_mut_shim!(_PyWeakref_ProxyType)) - || (Py_TYPE(op) == addr_of_mut_shim!(_PyWeakref_CallableProxyType))) as c_int + ((Py_TYPE(op) == addr_of_mut!(_PyWeakref_ProxyType)) + || (Py_TYPE(op) == addr_of_mut!(_PyWeakref_CallableProxyType))) as c_int } #[inline] diff --git a/src/conversions/std/array.rs b/src/conversions/std/array.rs index 6274bba7..0cbf3eb6 100644 --- a/src/conversions/std/array.rs +++ b/src/conversions/std/array.rs @@ -1,308 +1,118 @@ +use crate::conversion::{AsPyPointer, IntoPyPointer}; +use crate::types::PySequence; use crate::{exceptions, PyErr}; +use crate::{ + ffi, FromPyObject, IntoPy, Py, PyAny, PyDowncastError, PyObject, PyResult, Python, ToPyObject, +}; -#[cfg(min_const_generics)] -mod min_const_generics { - use super::invalid_sequence_length; - use crate::conversion::{AsPyPointer, IntoPyPointer}; - use crate::types::PySequence; - use crate::{ - ffi, FromPyObject, IntoPy, Py, PyAny, PyDowncastError, PyObject, PyResult, Python, - ToPyObject, - }; - - impl IntoPy for [T; N] - where - T: IntoPy, - { - fn into_py(self, py: Python<'_>) -> PyObject { - unsafe { - #[allow(deprecated)] // we're not on edition 2021 yet - let elements = std::array::IntoIter::new(self); - let len = N as ffi::Py_ssize_t; - - let ptr = ffi::PyList_New(len); - - // We create the `Py` pointer here for two reasons: - // - panics if the ptr is null - // - its Drop cleans up the list if user code panics. - let list: Py = Py::from_owned_ptr(py, ptr); - - for (i, obj) in (0..len).zip(elements) { - let obj = obj.into_py(py).into_ptr(); - - #[cfg(not(Py_LIMITED_API))] - ffi::PyList_SET_ITEM(ptr, i, obj); - #[cfg(Py_LIMITED_API)] - ffi::PyList_SetItem(ptr, i, obj); - } - - list - } - } - } - - impl ToPyObject for [T; N] - where - T: ToPyObject, - { - fn to_object(&self, py: Python<'_>) -> PyObject { - self.as_ref().to_object(py) - } - } - - impl<'a, T, const N: usize> FromPyObject<'a> for [T; N] - where - T: FromPyObject<'a>, - { - fn extract(obj: &'a PyAny) -> PyResult { - create_array_from_obj(obj) - } - } - - fn create_array_from_obj<'s, T, const N: usize>(obj: &'s PyAny) -> PyResult<[T; N]> - where - T: FromPyObject<'s>, - { - // Types that pass `PySequence_Check` usually implement enough of the sequence protocol - // to support this function and if not, we will only fail extraction safely. - let seq: &PySequence = unsafe { - if ffi::PySequence_Check(obj.as_ptr()) != 0 { - obj.downcast_unchecked() - } else { - return Err(PyDowncastError::new(obj, "Sequence").into()); - } - }; - let seq_len = seq.len()?; - if seq_len != N { - return Err(invalid_sequence_length(N, seq_len)); - } - array_try_from_fn(|idx| seq.get_item(idx).and_then(PyAny::extract)) - } - - // TODO use std::array::try_from_fn, if that stabilises: - // (https://github.com/rust-lang/rust/pull/75644) - fn array_try_from_fn(mut cb: F) -> Result<[T; N], E> - where - F: FnMut(usize) -> Result, - { - // Helper to safely create arrays since the standard library doesn't - // provide one yet. Shouldn't be necessary in the future. - struct ArrayGuard { - dst: *mut T, - initialized: usize, - } - - impl Drop for ArrayGuard { - fn drop(&mut self) { - debug_assert!(self.initialized <= N); - let initialized_part = - core::ptr::slice_from_raw_parts_mut(self.dst, self.initialized); - unsafe { - core::ptr::drop_in_place(initialized_part); - } - } - } - - // [MaybeUninit; N] would be "nicer" but is actually difficult to create - there are nightly - // APIs which would make this easier. - let mut array: core::mem::MaybeUninit<[T; N]> = core::mem::MaybeUninit::uninit(); - let mut guard: ArrayGuard = ArrayGuard { - dst: array.as_mut_ptr() as _, - initialized: 0, - }; +impl IntoPy for [T; N] +where + T: IntoPy, +{ + fn into_py(self, py: Python<'_>) -> PyObject { unsafe { - let mut value_ptr = array.as_mut_ptr() as *mut T; - for i in 0..N { - core::ptr::write(value_ptr, cb(i)?); - value_ptr = value_ptr.offset(1); - guard.initialized += 1; + #[allow(deprecated)] // we're not on edition 2021 yet + let elements = std::array::IntoIter::new(self); + let len = N as ffi::Py_ssize_t; + + let ptr = ffi::PyList_New(len); + + // We create the `Py` pointer here for two reasons: + // - panics if the ptr is null + // - its Drop cleans up the list if user code panics. + let list: Py = Py::from_owned_ptr(py, ptr); + + for (i, obj) in (0..len).zip(elements) { + let obj = obj.into_py(py).into_ptr(); + + #[cfg(not(Py_LIMITED_API))] + ffi::PyList_SET_ITEM(ptr, i, obj); + #[cfg(Py_LIMITED_API)] + ffi::PyList_SetItem(ptr, i, obj); } - core::mem::forget(guard); - Ok(array.assume_init()) - } - } - #[cfg(test)] - mod tests { - use super::*; - use std::{ - panic, - sync::atomic::{AtomicUsize, Ordering}, - }; - - #[test] - fn array_try_from_fn() { - static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); - struct CountDrop; - impl Drop for CountDrop { - fn drop(&mut self) { - DROP_COUNTER.fetch_add(1, Ordering::SeqCst); - } - } - let _ = catch_unwind_silent(move || { - let _: Result<[CountDrop; 4], ()> = super::array_try_from_fn(|idx| { - #[allow(clippy::manual_assert)] - if idx == 2 { - panic!("peek a boo"); - } - Ok(CountDrop) - }); - }); - assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2); - } - - #[test] - fn test_extract_bytearray_to_array() { - Python::with_gil(|py| { - let v: [u8; 33] = py - .eval( - "bytearray(b'abcabcabcabcabcabcabcabcabcabcabc')", - None, - None, - ) - .unwrap() - .extract() - .unwrap(); - assert!(&v == b"abcabcabcabcabcabcabcabcabcabcabc"); - }) - } - - // https://stackoverflow.com/a/59211505 - fn catch_unwind_silent(f: F) -> std::thread::Result - where - F: FnOnce() -> R + panic::UnwindSafe, - { - let prev_hook = panic::take_hook(); - panic::set_hook(Box::new(|_| {})); - let result = panic::catch_unwind(f); - panic::set_hook(prev_hook); - result + list } } } -#[cfg(not(min_const_generics))] -mod array_impls { - use super::invalid_sequence_length; - use crate::conversion::{AsPyPointer, IntoPyPointer}; - use crate::types::PySequence; - use crate::{ - ffi, FromPyObject, IntoPy, Py, PyAny, PyDowncastError, PyObject, PyResult, Python, - ToPyObject, +impl ToPyObject for [T; N] +where + T: ToPyObject, +{ + fn to_object(&self, py: Python<'_>) -> PyObject { + self.as_ref().to_object(py) + } +} + +impl<'a, T, const N: usize> FromPyObject<'a> for [T; N] +where + T: FromPyObject<'a>, +{ + fn extract(obj: &'a PyAny) -> PyResult { + create_array_from_obj(obj) + } +} + +fn create_array_from_obj<'s, T, const N: usize>(obj: &'s PyAny) -> PyResult<[T; N]> +where + T: FromPyObject<'s>, +{ + // Types that pass `PySequence_Check` usually implement enough of the sequence protocol + // to support this function and if not, we will only fail extraction safely. + let seq: &PySequence = unsafe { + if ffi::PySequence_Check(obj.as_ptr()) != 0 { + obj.downcast_unchecked() + } else { + return Err(PyDowncastError::new(obj, "Sequence").into()); + } }; - use std::mem::{transmute_copy, ManuallyDrop}; + let seq_len = seq.len()?; + if seq_len != N { + return Err(invalid_sequence_length(N, seq_len)); + } + array_try_from_fn(|idx| seq.get_item(idx).and_then(PyAny::extract)) +} - macro_rules! array_impls { - ($($N:expr),+) => { - $( - impl IntoPy for [T; $N] - where - T: IntoPy - { - fn into_py(self, py: Python<'_>) -> PyObject { +// TODO use std::array::try_from_fn, if that stabilises: +// (https://github.com/rust-lang/rust/pull/75644) +fn array_try_from_fn(mut cb: F) -> Result<[T; N], E> +where + F: FnMut(usize) -> Result, +{ + // Helper to safely create arrays since the standard library doesn't + // provide one yet. Shouldn't be necessary in the future. + struct ArrayGuard { + dst: *mut T, + initialized: usize, + } - struct ArrayGuard { - elements: [ManuallyDrop; $N], - start: usize, - } - - impl Drop for ArrayGuard { - fn drop(&mut self) { - unsafe { - let needs_drop = self.elements.get_mut(self.start..).unwrap(); - for item in needs_drop { - ManuallyDrop::drop(item); - } - } - } - } - - unsafe { - let ptr = ffi::PyList_New($N as ffi::Py_ssize_t); - - // We create the `Py` pointer here for two reasons: - // - panics if the ptr is null - // - its Drop cleans up the list if user code panics. - let list: Py = Py::from_owned_ptr(py, ptr); - - let slf = ManuallyDrop::new(self); - - let mut guard = ArrayGuard { - // the transmute size check is _very_ dumb around generics - elements: transmute_copy(&slf), - start: 0 - }; - - for i in 0..$N { - let obj: T = ManuallyDrop::take(&mut guard.elements[i]); - guard.start += 1; - - let obj = obj.into_py(py).into_ptr(); - - #[cfg(not(Py_LIMITED_API))] - ffi::PyList_SET_ITEM(ptr, i as ffi::Py_ssize_t, obj); - #[cfg(Py_LIMITED_API)] - ffi::PyList_SetItem(ptr, i as ffi::Py_ssize_t, obj); - } - - std::mem::forget(guard); - - list - } - } - } - - impl ToPyObject for [T; $N] - where - T: ToPyObject, - { - fn to_object(&self, py: Python<'_>) -> PyObject { - self.as_ref().to_object(py) - } - } - - impl<'a, T> FromPyObject<'a> for [T; $N] - where - T: Copy + Default + FromPyObject<'a>, - { - fn extract(obj: &'a PyAny) -> PyResult { - let mut array = [T::default(); $N]; - extract_sequence_into_slice(obj, &mut array)?; - Ok(array) - } - } - )+ + impl Drop for ArrayGuard { + fn drop(&mut self) { + debug_assert!(self.initialized <= N); + let initialized_part = core::ptr::slice_from_raw_parts_mut(self.dst, self.initialized); + unsafe { + core::ptr::drop_in_place(initialized_part); + } } } - #[cfg(not(min_const_generics))] - array_impls!( - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32 - ); - - #[cfg(not(min_const_generics))] - fn extract_sequence_into_slice<'s, T>(obj: &'s PyAny, slice: &mut [T]) -> PyResult<()> - where - T: FromPyObject<'s>, - { - // Types that pass `PySequence_Check` usually implement enough of the sequence protocol - // to support this function and if not, we will only fail extraction safely. - let seq: &PySequence = unsafe { - if ffi::PySequence_Check(obj.as_ptr()) != 0 { - obj.downcast_unchecked() - } else { - return Err(PyDowncastError::new(obj, "Sequence").into()); - } - }; - let seq_len = seq.len()?; - if seq_len != slice.len() { - return Err(invalid_sequence_length(slice.len(), seq_len)); + // [MaybeUninit; N] would be "nicer" but is actually difficult to create - there are nightly + // APIs which would make this easier. + let mut array: core::mem::MaybeUninit<[T; N]> = core::mem::MaybeUninit::uninit(); + let mut guard: ArrayGuard = ArrayGuard { + dst: array.as_mut_ptr() as _, + initialized: 0, + }; + unsafe { + let mut value_ptr = array.as_mut_ptr() as *mut T; + for i in 0..N { + core::ptr::write(value_ptr, cb(i)?); + value_ptr = value_ptr.offset(1); + guard.initialized += 1; } - for (value, item) in slice.iter_mut().zip(seq.iter()?) { - *value = item?.extract::()?; - } - Ok(()) + core::mem::forget(guard); + Ok(array.assume_init()) } } @@ -315,8 +125,50 @@ fn invalid_sequence_length(expected: usize, actual: usize) -> PyErr { #[cfg(test)] mod tests { + use std::{ + panic, + sync::atomic::{AtomicUsize, Ordering}, + }; + use crate::{types::PyList, IntoPy, PyResult, Python, ToPyObject}; + #[test] + fn array_try_from_fn() { + static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); + struct CountDrop; + impl Drop for CountDrop { + fn drop(&mut self) { + DROP_COUNTER.fetch_add(1, Ordering::SeqCst); + } + } + let _ = catch_unwind_silent(move || { + let _: Result<[CountDrop; 4], ()> = super::array_try_from_fn(|idx| { + #[allow(clippy::manual_assert)] + if idx == 2 { + panic!("peek a boo"); + } + Ok(CountDrop) + }); + }); + assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2); + } + + #[test] + fn test_extract_bytearray_to_array() { + Python::with_gil(|py| { + let v: [u8; 33] = py + .eval( + "bytearray(b'abcabcabcabcabcabcabcabcabcabcabc')", + None, + None, + ) + .unwrap() + .extract() + .unwrap(); + assert!(&v == b"abcabcabcabcabcabcabcabcabcabcabc"); + }) + } + #[test] fn test_extract_small_bytearray_to_array() { Python::with_gil(|py| { @@ -390,4 +242,16 @@ mod tests { let _cell: &crate::PyCell = list.get_item(4).unwrap().extract().unwrap(); }); } + + // https://stackoverflow.com/a/59211505 + fn catch_unwind_silent(f: F) -> std::thread::Result + where + F: FnOnce() -> R + panic::UnwindSafe, + { + let prev_hook = panic::take_hook(); + panic::set_hook(Box::new(|_| {})); + let result = panic::catch_unwind(f); + panic::set_hook(prev_hook); + result + } } diff --git a/src/impl_/extract_argument.rs b/src/impl_/extract_argument.rs index dd361e4b..764a4e3c 100644 --- a/src/impl_/extract_argument.rs +++ b/src/impl_/extract_argument.rs @@ -50,13 +50,6 @@ pub fn extract_pyclass_ref<'a, 'py: 'a, T: PyClass>( obj: &'py PyAny, holder: &'a mut Option>, ) -> PyResult<&'a T> { - #[cfg(not(option_insert))] - { - *holder = Some(obj.extract()?); - return Ok(holder.as_deref().unwrap()); - } - - #[cfg(option_insert)] Ok(&*holder.insert(obj.extract()?)) } @@ -65,13 +58,6 @@ pub fn extract_pyclass_ref_mut<'a, 'py: 'a, T: PyClass>( obj: &'py PyAny, holder: &'a mut Option>, ) -> PyResult<&'a mut T> { - #[cfg(not(option_insert))] - { - *holder = Some(obj.extract()?); - return Ok(holder.as_deref_mut().unwrap()); - } - - #[cfg(option_insert)] Ok(&mut *holder.insert(obj.extract()?)) } diff --git a/tests/test_class_attributes.rs b/tests/test_class_attributes.rs index e07aa457..781cc799 100644 --- a/tests/test_class_attributes.rs +++ b/tests/test_class_attributes.rs @@ -96,7 +96,6 @@ fn recursive_class_attributes() { } #[test] -#[cfg_attr(cfg_panic, cfg(panic = "unwind"))] fn test_fallible_class_attribute() { use pyo3::{exceptions::PyValueError, types::PyString}; diff --git a/tests/not_msrv/requires_1_54.rs b/tests/test_macro_docs.rs similarity index 93% rename from tests/not_msrv/requires_1_54.rs rename to tests/test_macro_docs.rs index 8a68fdee..8c392821 100644 --- a/tests/not_msrv/requires_1_54.rs +++ b/tests/test_macro_docs.rs @@ -1,8 +1,10 @@ +#![cfg(feature = "macros")] + use pyo3::prelude::*; use pyo3::types::IntoPyDict; #[macro_use] -#[path = "../common.rs"] +#[path = "common.rs"] mod common; #[pyclass] diff --git a/tests/test_not_msrv.rs b/tests/test_not_msrv.rs deleted file mode 100644 index b0d1eba8..00000000 --- a/tests/test_not_msrv.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![cfg(feature = "macros")] - -//! Functionality which is not only not supported on MSRV, -//! but can't even be cfg-ed out on MSRV because the compiler doesn't support -//! the syntax. - -#[rustversion::since(1.54)] -mod requires_1_54 { - - include!("not_msrv/requires_1_54.rs"); -} diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 48a5a63f..bdd52175 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -11,6 +11,5 @@ name = "xtask" anyhow = "1.0.51" # Clap 3 requires MSRV 1.54 -rustversion = "1.0" structopt = { version = "0.3", default-features = false } clap = { version = "2" } diff --git a/xtask/src/cli.rs b/xtask/src/cli.rs index fa8d1636..ec674ec6 100644 --- a/xtask/src/cli.rs +++ b/xtask/src/cli.rs @@ -107,7 +107,7 @@ impl Subcommand { /// Run a command as a child process, inheriting stdin, stdout and stderr. pub fn run(command: &mut Command) -> Result<()> { - let command_str = format_command(command); + let command_str = format!("{:?}", command); let github_actions = std::env::var_os("GITHUB_ACTIONS").is_some(); if github_actions { println!("::group::Running: {}", command_str); @@ -135,7 +135,7 @@ pub fn run(command: &mut Command) -> Result<()> { /// Like `run`, but does not inherit stdin, stdout and stderr. pub fn run_with_output(command: &mut Command) -> Result { - let command_str = format_command(command); + let command_str = format!("{:?}", command); println!("Running: {}", command_str); diff --git a/xtask/src/utils.rs b/xtask/src/utils.rs index 045697e7..b6941263 100644 --- a/xtask/src/utils.rs +++ b/xtask/src/utils.rs @@ -1,47 +1,16 @@ use anyhow::ensure; use std::process::Command; -// Replacement for str.split_once() on Rust older than 1.52 -#[rustversion::before(1.52)] -pub fn split_once(s: &str, pat: char) -> Option<(&str, &str)> { - let mut iter = s.splitn(2, pat); - Some((iter.next()?, iter.next()?)) -} - -#[rustversion::since(1.52)] -pub fn split_once(s: &str, pat: char) -> Option<(&str, &str)> { - s.split_once(pat) -} - -#[rustversion::since(1.57)] -pub fn format_command(command: &Command) -> String { - let mut buf = String::new(); - buf.push('`'); - buf.push_str(&command.get_program().to_string_lossy()); - for arg in command.get_args() { - buf.push(' '); - buf.push_str(&arg.to_string_lossy()); - } - buf.push('`'); - buf -} - -#[rustversion::before(1.57)] -pub fn format_command(command: &Command) -> String { - // Debug impl isn't as nice as the above, but will do on < 1.57 - format!("{:?}", command) -} - pub fn get_output(command: &mut Command) -> anyhow::Result { let output = command.output()?; ensure! { output.status.success(), - "process did not run successfully ({exit}): {command}", + "process did not run successfully ({exit}): {command:?}", exit = match output.status.code() { Some(code) => format!("exit code {}", code), None => "terminated by signal".into(), }, - command = format_command(command), + command = command, }; Ok(output) }