Remove cfg min_const_generics made unnecessary by MSRV bump.
This commit is contained in:
parent
f7bd6ce224
commit
eb04f54683
2
build.rs
2
build.rs
|
@ -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(())
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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(())
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue