diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 7e9834087..d0a0c0118 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -34,7 +34,7 @@ jobs:
- stable
- beta
- nightly
- - 1.51.0 # MSRV
+ - 1.57.0 # MSRV
name: tests/${{ matrix.rust }}
steps:
diff --git a/Cargo.toml b/Cargo.toml
index a648b09bc..ae9e33f06 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,7 +3,7 @@
name = "ndarray"
version = "0.15.6"
edition = "2018"
-rust-version = "1.51"
+rust-version = "1.57"
authors = [
"Ulrik Sverdrup \"bluss\"",
"Jim Turner"
diff --git a/scripts/all-tests.sh b/scripts/all-tests.sh
index 81d240ba2..cbea6dba7 100755
--- a/scripts/all-tests.sh
+++ b/scripts/all-tests.sh
@@ -6,7 +6,7 @@ set -e
FEATURES=$1
CHANNEL=$2
-if [ "$CHANNEL" = "1.51.0" ]; then
+if [ "$CHANNEL" = "1.57.0" ]; then
cargo update --package openblas-src --precise 0.10.5
cargo update --package openblas-build --precise 0.10.5
cargo update --package once_cell --precise 1.14.0
diff --git a/src/aliases.rs b/src/aliases.rs
index d41c888a6..9a8ea8f2c 100644
--- a/src/aliases.rs
+++ b/src/aliases.rs
@@ -7,43 +7,43 @@ use crate::{ArcArray, Array, ArrayView, ArrayViewMut, Ix, IxDynImpl};
/// Create a zero-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
-pub fn Ix0() -> Ix0 {
+pub const fn Ix0() -> Ix0 {
Dim::new([])
}
/// Create a one-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
-pub fn Ix1(i0: Ix) -> Ix1 {
+pub const fn Ix1(i0: Ix) -> Ix1 {
Dim::new([i0])
}
/// Create a two-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
-pub fn Ix2(i0: Ix, i1: Ix) -> Ix2 {
+pub const fn Ix2(i0: Ix, i1: Ix) -> Ix2 {
Dim::new([i0, i1])
}
/// Create a three-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
-pub fn Ix3(i0: Ix, i1: Ix, i2: Ix) -> Ix3 {
+pub const fn Ix3(i0: Ix, i1: Ix, i2: Ix) -> Ix3 {
Dim::new([i0, i1, i2])
}
/// Create a four-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
-pub fn Ix4(i0: Ix, i1: Ix, i2: Ix, i3: Ix) -> Ix4 {
+pub const fn Ix4(i0: Ix, i1: Ix, i2: Ix, i3: Ix) -> Ix4 {
Dim::new([i0, i1, i2, i3])
}
/// Create a five-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
-pub fn Ix5(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix) -> Ix5 {
+pub const fn Ix5(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix) -> Ix5 {
Dim::new([i0, i1, i2, i3, i4])
}
/// Create a six-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
-pub fn Ix6(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix, i5: Ix) -> Ix6 {
+pub const fn Ix6(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix, i5: Ix) -> Ix6 {
Dim::new([i0, i1, i2, i3, i4, i5])
}
diff --git a/src/arraytraits.rs b/src/arraytraits.rs
index 39a82b1ae..8d44c1e72 100644
--- a/src/arraytraits.rs
+++ b/src/arraytraits.rs
@@ -307,6 +307,10 @@ pub const ARRAY_FORMAT_VERSION: u8 = 1u8;
// use "raw" form instead of type aliases here so that they show up in docs
/// Implementation of `ArrayView::from(&S)` where `S` is a slice or sliceable.
+///
+/// **Panics** if the length of the slice overflows `isize`. (This can only
+/// occur if `A` is zero-sized, because slices cannot contain more than
+/// `isize::MAX` number of bytes.)
impl<'a, A, Slice: ?Sized> From<&'a Slice> for ArrayView<'a, A, Ix1>
where
Slice: AsRef<[A]>,
@@ -315,14 +319,7 @@ where
///
/// **Panics** if the slice length is greater than `isize::MAX`.
fn from(slice: &'a Slice) -> Self {
- let xs = slice.as_ref();
- if mem::size_of::() == 0 {
- assert!(
- xs.len() <= ::std::isize::MAX as usize,
- "Slice length must fit in `isize`.",
- );
- }
- unsafe { Self::from_shape_ptr(xs.len(), xs.as_ptr()) }
+ aview1(slice.as_ref())
}
}
@@ -334,25 +331,7 @@ where
impl<'a, A, const N: usize> From<&'a [[A; N]]> for ArrayView<'a, A, Ix2> {
/// Create a two-dimensional read-only array view of the data in `slice`
fn from(xs: &'a [[A; N]]) -> Self {
- let cols = N;
- let rows = xs.len();
- let dim = Ix2(rows, cols);
- if size_of::() == 0 {
- dimension::size_of_shape_checked(&dim)
- .expect("Product of non-zero axis lengths must not overflow isize.");
- } else if N == 0 {
- assert!(
- xs.len() <= isize::MAX as usize,
- "Product of non-zero axis lengths must not overflow isize.",
- );
- }
-
- // `cols * rows` is guaranteed to fit in `isize` because we checked that it fits in
- // `isize::MAX`
- unsafe {
- let data = slice::from_raw_parts(xs.as_ptr() as *const A, cols * rows);
- ArrayView::from_shape_ptr(dim, data.as_ptr())
- }
+ aview2(xs)
}
}
diff --git a/src/dimension/dim.rs b/src/dimension/dim.rs
index 19075f943..3f8ff23e3 100644
--- a/src/dimension/dim.rs
+++ b/src/dimension/dim.rs
@@ -42,7 +42,7 @@ pub struct Dim {
impl Dim {
/// Private constructor and accessors for Dim
- pub(crate) fn new(index: I) -> Dim {
+ pub(crate) const fn new(index: I) -> Dim {
Dim { index }
}
#[inline(always)]
diff --git a/src/free_functions.rs b/src/free_functions.rs
index e9c3abff6..342aae980 100644
--- a/src/free_functions.rs
+++ b/src/free_functions.rs
@@ -10,6 +10,7 @@ use alloc::vec;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use std::mem::{forget, size_of};
+use std::ptr::NonNull;
use crate::imp_prelude::*;
use crate::{dimension, ArcArray1, ArcArray2};
@@ -65,14 +66,24 @@ pub fn rcarr1(xs: &[A]) -> ArcArray1 {
}
/// Create a zero-dimensional array view borrowing `x`.
-pub fn aview0(x: &A) -> ArrayView0<'_, A> {
- unsafe { ArrayView::from_shape_ptr(Ix0(), x) }
+pub const fn aview0(x: &A) -> ArrayView0<'_, A> {
+ ArrayBase {
+ data: ViewRepr::new(),
+ // Safe because references are always non-null.
+ ptr: unsafe { NonNull::new_unchecked(x as *const A as *mut A) },
+ dim: Ix0(),
+ strides: Ix0(),
+ }
}
/// Create a one-dimensional array view with elements borrowing `xs`.
///
+/// **Panics** if the length of the slice overflows `isize`. (This can only
+/// occur if `A` is zero-sized, because slices cannot contain more than
+/// `isize::MAX` number of bytes.)
+///
/// ```
-/// use ndarray::aview1;
+/// use ndarray::{aview1, ArrayView1};
///
/// let data = [1.0; 1024];
///
@@ -80,17 +91,80 @@ pub fn aview0(x: &A) -> ArrayView0<'_, A> {
/// let a2d = aview1(&data).into_shape((32, 32)).unwrap();
///
/// assert_eq!(a2d.sum(), 1024.0);
+///
+/// // Create a const 1D array view
+/// const C: ArrayView1<'static, f64> = aview1(&[1., 2., 3.]);
+///
+/// assert_eq!(C.sum(), 6.);
/// ```
-pub fn aview1(xs: &[A]) -> ArrayView1<'_, A> {
- ArrayView::from(xs)
+pub const fn aview1(xs: &[A]) -> ArrayView1<'_, A> {
+ if size_of::() == 0 {
+ assert!(
+ xs.len() <= isize::MAX as usize,
+ "Slice length must fit in `isize`.",
+ );
+ }
+ ArrayBase {
+ data: ViewRepr::new(),
+ // Safe because references are always non-null.
+ ptr: unsafe { NonNull::new_unchecked(xs.as_ptr() as *mut A) },
+ dim: Ix1(xs.len()),
+ strides: Ix1(1),
+ }
}
/// Create a two-dimensional array view with elements borrowing `xs`.
///
-/// **Panics** if the product of non-zero axis lengths overflows `isize` (This can only occur if A
-/// is zero-sized because slices cannot contain more than `isize::MAX` number of bytes).
-pub fn aview2(xs: &[[A; N]]) -> ArrayView2<'_, A> {
- ArrayView2::from(xs)
+/// **Panics** if the product of non-zero axis lengths overflows `isize` (This
+/// can only occur if A is zero-sized or if `N` is zero, because slices cannot
+/// contain more than `isize::MAX` number of bytes).
+///
+/// ```
+/// use ndarray::{aview2, ArrayView2};
+///
+/// let data = vec![[1., 2., 3.], [4., 5., 6.]];
+///
+/// let view = aview2(&data);
+/// assert_eq!(view.sum(), 21.);
+///
+/// // Create a const 2D array view
+/// const C: ArrayView2<'static, f64> = aview2(&[[1., 2., 3.], [4., 5., 6.]]);
+/// assert_eq!(C.sum(), 21.);
+/// ```
+pub const fn aview2(xs: &[[A; N]]) -> ArrayView2<'_, A> {
+ let cols = N;
+ let rows = xs.len();
+ if size_of::() == 0 {
+ if let Some(n_elems) = rows.checked_mul(cols) {
+ assert!(
+ rows <= isize::MAX as usize
+ && cols <= isize::MAX as usize
+ && n_elems <= isize::MAX as usize,
+ "Product of non-zero axis lengths must not overflow isize.",
+ );
+ } else {
+ panic!("Overflow in number of elements.");
+ }
+ } else if N == 0 {
+ assert!(
+ rows <= isize::MAX as usize,
+ "Product of non-zero axis lengths must not overflow isize.",
+ );
+ }
+ // Safe because references are always non-null.
+ let ptr = unsafe { NonNull::new_unchecked(xs.as_ptr() as *mut A) };
+ let dim = Ix2(rows, cols);
+ let strides = if rows == 0 || cols == 0 {
+ Ix2(0, 0)
+ } else {
+ Ix2(cols, 1)
+ };
+ ArrayBase {
+ data: ViewRepr::new(),
+ ptr,
+ dim,
+ strides,
+ }
}
/// Create a one-dimensional read-write array view with elements borrowing `xs`.
diff --git a/src/lib.rs b/src/lib.rs
index a651ae58c..b15b0ea88 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -71,7 +71,7 @@
//! needs matching memory layout to be efficient (with some exceptions).
//! + Efficient floating point matrix multiplication even for very large
//! matrices; can optionally use BLAS to improve it further.
-//! - **Requires Rust 1.51 or later**
+//! - **Requires Rust 1.57 or later**
//!
//! ## Crate Feature Flags
//!
@@ -1450,7 +1450,7 @@ pub struct RawViewRepr {
impl RawViewRepr {
#[inline(always)]
- fn new() -> Self {
+ const fn new() -> Self {
RawViewRepr { ptr: PhantomData }
}
}
@@ -1467,7 +1467,7 @@ pub struct ViewRepr {
impl ViewRepr {
#[inline(always)]
- fn new() -> Self {
+ const fn new() -> Self {
ViewRepr { life: PhantomData }
}
}