Remove cfg min_const_generics made unnecessary by MSRV bump.

This commit is contained in:
Adam Reichold 2023-06-05 09:42:40 +02:00
parent f7bd6ce224
commit eb04f54683
4 changed files with 155 additions and 296 deletions

View File

@ -46,7 +46,7 @@ fn configure_pyo3() -> Result<()> {
ensure_auto_initialize_ok(interpreter_config)?; 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(); print_feature_cfgs();
Ok(()) Ok(())

View File

@ -142,11 +142,6 @@ pub fn print_feature_cfgs() {
let rustc_minor_version = rustc_minor_version().unwrap_or(0); 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 // Enable use of std::ptr::addr_of! on Rust 1.51 and greater
if rustc_minor_version >= 51 { if rustc_minor_version >= 51 {
println!("cargo:rustc-cfg=addr_of"); println!("cargo:rustc-cfg=addr_of");

View File

@ -100,7 +100,7 @@ fn configure_pyo3() -> Result<()> {
println!("{}", line); println!("{}", line);
} }
// Emit cfgs like `addr_of` and `min_const_generics` // Emit cfgs like `thread_local_const_init`
print_feature_cfgs(); print_feature_cfgs();
Ok(()) Ok(())

View File

@ -1,19 +1,14 @@
use crate::conversion::{AsPyPointer, IntoPyPointer};
use crate::types::PySequence;
use crate::{exceptions, PyErr}; use crate::{exceptions, PyErr};
use crate::{
ffi, FromPyObject, IntoPy, Py, PyAny, PyDowncastError, PyObject, PyResult, Python, ToPyObject,
};
#[cfg(min_const_generics)] impl<T, const N: usize> IntoPy<PyObject> for [T; N]
mod min_const_generics { where
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>, T: IntoPy<PyObject>,
{ {
fn into_py(self, py: Python<'_>) -> PyObject { fn into_py(self, py: Python<'_>) -> PyObject {
unsafe { unsafe {
#[allow(deprecated)] // we're not on edition 2021 yet #[allow(deprecated)] // we're not on edition 2021 yet
@ -39,30 +34,30 @@ mod min_const_generics {
list list
} }
} }
} }
impl<T, const N: usize> ToPyObject for [T; N] impl<T, const N: usize> ToPyObject for [T; N]
where where
T: ToPyObject, T: ToPyObject,
{ {
fn to_object(&self, py: Python<'_>) -> PyObject { fn to_object(&self, py: Python<'_>) -> PyObject {
self.as_ref().to_object(py) self.as_ref().to_object(py)
} }
} }
impl<'a, T, const N: usize> FromPyObject<'a> for [T; N] impl<'a, T, const N: usize> FromPyObject<'a> for [T; N]
where where
T: FromPyObject<'a>, T: FromPyObject<'a>,
{ {
fn extract(obj: &'a PyAny) -> PyResult<Self> { fn extract(obj: &'a PyAny) -> PyResult<Self> {
create_array_from_obj(obj) create_array_from_obj(obj)
} }
} }
fn create_array_from_obj<'s, T, const N: usize>(obj: &'s PyAny) -> PyResult<[T; N]> fn create_array_from_obj<'s, T, const N: usize>(obj: &'s PyAny) -> PyResult<[T; N]>
where where
T: FromPyObject<'s>, T: FromPyObject<'s>,
{ {
// Types that pass `PySequence_Check` usually implement enough of the sequence protocol // 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. // to support this function and if not, we will only fail extraction safely.
let seq: &PySequence = unsafe { let seq: &PySequence = unsafe {
@ -77,14 +72,14 @@ mod min_const_generics {
return Err(invalid_sequence_length(N, seq_len)); return Err(invalid_sequence_length(N, seq_len));
} }
array_try_from_fn(|idx| seq.get_item(idx).and_then(PyAny::extract)) array_try_from_fn(|idx| seq.get_item(idx).and_then(PyAny::extract))
} }
// TODO use std::array::try_from_fn, if that stabilises: // TODO use std::array::try_from_fn, if that stabilises:
// (https://github.com/rust-lang/rust/pull/75644) // (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> fn array_try_from_fn<E, F, T, const N: usize>(mut cb: F) -> Result<[T; N], E>
where where
F: FnMut(usize) -> Result<T, E>, F: FnMut(usize) -> Result<T, E>,
{ {
// Helper to safely create arrays since the standard library doesn't // Helper to safely create arrays since the standard library doesn't
// provide one yet. Shouldn't be necessary in the future. // provide one yet. Shouldn't be necessary in the future.
struct ArrayGuard<T, const N: usize> { struct ArrayGuard<T, const N: usize> {
@ -95,8 +90,7 @@ mod min_const_generics {
impl<T, const N: usize> Drop for ArrayGuard<T, N> { impl<T, const N: usize> Drop for ArrayGuard<T, N> {
fn drop(&mut self) { fn drop(&mut self) {
debug_assert!(self.initialized <= N); debug_assert!(self.initialized <= N);
let initialized_part = let initialized_part = core::ptr::slice_from_raw_parts_mut(self.dst, self.initialized);
core::ptr::slice_from_raw_parts_mut(self.dst, self.initialized);
unsafe { unsafe {
core::ptr::drop_in_place(initialized_part); core::ptr::drop_in_place(initialized_part);
} }
@ -120,16 +114,24 @@ mod min_const_generics {
core::mem::forget(guard); core::mem::forget(guard);
Ok(array.assume_init()) Ok(array.assume_init())
} }
} }
#[cfg(test)] fn invalid_sequence_length(expected: usize, actual: usize) -> PyErr {
mod tests { exceptions::PyValueError::new_err(format!(
use super::*; "expected a sequence of length {} (got {})",
expected, actual
))
}
#[cfg(test)]
mod tests {
use std::{ use std::{
panic, panic,
sync::atomic::{AtomicUsize, Ordering}, sync::atomic::{AtomicUsize, Ordering},
}; };
use crate::{types::PyList, IntoPy, PyResult, Python, ToPyObject};
#[test] #[test]
fn array_try_from_fn() { fn array_try_from_fn() {
static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
@ -167,156 +169,6 @@ mod min_const_generics {
}) })
} }
// 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
}
}
}
#[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,
};
use std::mem::{transmute_copy, ManuallyDrop};
macro_rules! array_impls {
($($N:expr),+) => {
$(
impl<T> IntoPy<PyObject> for [T; $N]
where
T: IntoPy<PyObject>
{
fn into_py(self, py: Python<'_>) -> PyObject {
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)
}
}
)+
}
}
#[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));
}
for (value, item) in slice.iter_mut().zip(seq.iter()?) {
*value = item?.extract::<T>()?;
}
Ok(())
}
}
fn invalid_sequence_length(expected: usize, actual: usize) -> PyErr {
exceptions::PyValueError::new_err(format!(
"expected a sequence of length {} (got {})",
expected, actual
))
}
#[cfg(test)]
mod tests {
use crate::{types::PyList, IntoPy, PyResult, Python, ToPyObject};
#[test] #[test]
fn test_extract_small_bytearray_to_array() { fn test_extract_small_bytearray_to_array() {
Python::with_gil(|py| { Python::with_gil(|py| {
@ -390,4 +242,16 @@ mod tests {
let _cell: &crate::PyCell<Foo> = list.get_item(4).unwrap().extract().unwrap(); 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
}
} }