3209: Remove the conditional compilation flags which are made redundant  by the MSRV bump r=davidhewitt a=adamreichold



Co-authored-by: Adam Reichold <adam.reichold@t-online.de>
This commit is contained in:
bors[bot] 2023-06-05 14:09:05 +00:00 committed by GitHub
commit e1f028f3e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 255 additions and 451 deletions

View File

@ -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"

View File

@ -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"

View File

@ -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(())

View File

@ -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

View File

@ -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

View File

@ -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(())

View File

@ -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]

View File

@ -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" {

View File

@ -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" {

View File

@ -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" {

View File

@ -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" {

View File

@ -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]

View File

@ -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" {

View File

@ -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" {

View File

@ -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

View File

@ -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]

View File

@ -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]

View File

@ -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

View File

@ -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" {

View File

@ -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::*;

View File

@ -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" {

View File

@ -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" {

View File

@ -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

View File

@ -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 =

View File

@ -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" {

View File

@ -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
}

View File

@ -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" {

View File

@ -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
}

View File

@ -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
}

View File

@ -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" {

View File

@ -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
}

View File

@ -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" {

View File

@ -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;

View File

@ -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]

View File

@ -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<T, const N: usize> IntoPy<PyObject> for [T; N]
where
T: IntoPy<PyObject>,
{
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<PyAny> = 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<T, const N: usize> 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<Self> {
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<E, F, T, const N: usize>(mut cb: F) -> Result<[T; N], E>
where
F: FnMut(usize) -> Result<T, E>,
{
// Helper to safely create arrays since the standard library doesn't
// provide one yet. Shouldn't be necessary in the future.
struct ArrayGuard<T, const N: usize> {
dst: *mut T,
initialized: usize,
}
impl<T, const N: usize> Drop for ArrayGuard<T, N> {
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<T>; 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<T, N> = ArrayGuard {
dst: array.as_mut_ptr() as _,
initialized: 0,
};
impl<T, const N: usize> IntoPy<PyObject> for [T; N]
where
T: IntoPy<PyObject>,
{
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<PyAny> = 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, R>(f: F) -> std::thread::Result<R>
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<T, const N: usize> 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<Self> {
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<T> IntoPy<PyObject> for [T; $N]
where
T: IntoPy<PyObject>
{
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<E, F, T, const N: usize>(mut cb: F) -> Result<[T; N], E>
where
F: FnMut(usize) -> Result<T, E>,
{
// Helper to safely create arrays since the standard library doesn't
// provide one yet. Shouldn't be necessary in the future.
struct ArrayGuard<T, const N: usize> {
dst: *mut T,
initialized: usize,
}
struct ArrayGuard<T> {
elements: [ManuallyDrop<T>; $N],
start: usize,
}
impl<T> Drop for ArrayGuard<T> {
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<PyAny> = 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<T> 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<Self> {
let mut array = [T::default(); $N];
extract_sequence_into_slice(obj, &mut array)?;
Ok(array)
}
}
)+
impl<T, const N: usize> Drop for ArrayGuard<T, N> {
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<T>; 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<T, N> = 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::<T>()?;
}
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<Foo> = list.get_item(4).unwrap().extract().unwrap();
});
}
// https://stackoverflow.com/a/59211505
fn catch_unwind_silent<F, R>(f: F) -> std::thread::Result<R>
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
}
}

View File

@ -50,13 +50,6 @@ pub fn extract_pyclass_ref<'a, 'py: 'a, T: PyClass>(
obj: &'py PyAny,
holder: &'a mut Option<PyRef<'py, T>>,
) -> 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<Frozen = False>>(
obj: &'py PyAny,
holder: &'a mut Option<PyRefMut<'py, T>>,
) -> 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()?))
}

View File

@ -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};

View File

@ -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]

View File

@ -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");
}

View File

@ -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" }

View File

@ -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<Output> {
let command_str = format_command(command);
let command_str = format!("{:?}", command);
println!("Running: {}", command_str);

View File

@ -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<std::process::Output> {
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)
}