Struct Slice

Source
pub struct Slice { /* private fields */ }
Expand description

Slice is a compact representation of indices into the flat representation of an n-dimensional array. Given an offset, sizes of each dimension, and strides for each dimension, Slice can compute indices into the flat array.

For example, the following describes a dense 4x4x4 array in row-major order:

let s = Slice::new(0, vec![4, 4, 4], vec![16, 4, 1]).unwrap();
assert!(s.iter().eq(0..(4 * 4 * 4)));

Slices allow easy slicing by subsetting and striding. For example, we can fix the index of the second dimension by dropping it and adding that index (multiplied by the previous size) to the offset.

let s = Slice::new(0, vec![2, 4, 2], vec![8, 2, 1]).unwrap();
let selected_index = 3;
let sub = Slice::new(2 * selected_index, vec![2, 2], vec![8, 1]).unwrap();
let coords = [[0, 0], [0, 1], [1, 0], [1, 1]];
for coord @ [x, y] in coords {
    assert_eq!(
        sub.location(&coord).unwrap(),
        s.location(&[x, 3, y]).unwrap()
    );
}

Implementations§

Source§

impl Slice

Source

pub fn new( offset: usize, sizes: Vec<usize>, strides: Vec<usize>, ) -> Result<Self, SliceError>

Create a new Slice with the provided offset, sizes, and strides. New performs validation to ensure that sizes and strides are compatible:

  • They have to be the same length (i.e., same number of dimensions)
  • They have to be rectangular (i.e., stride n+1 has to evenly divide into stride n)
  • Strides must be nonoverlapping (each stride has to be larger than the previous space)
Source

pub fn into_inner(self) -> (usize, Vec<usize>, Vec<usize>)

Deconstruct the slice into its offset, sizes, and strides.

Source

pub fn new_row_major(sizes: impl Into<Vec<usize>>) -> Self

Create a new slice of the given sizes in row-major order.

Source

pub fn new_single_multi_dim_cell(dims: usize) -> Self

Create one celled slice.

Source

pub fn num_dim(&self) -> usize

The number of dimensions in this slice.

Source

pub fn offset(&self) -> usize

This is the offset from which the first value in the Slice begins.

Source

pub fn sizes(&self) -> &[usize]

The shape of the slice; that is, the size of each dimension.

Source

pub fn strides(&self) -> &[usize]

The strides of the slice; that is, the distance between each element at a given index in the underlying array.

Source

pub fn is_contiguous(&self) -> bool

Source

pub fn at(&self, dim: usize, index: usize) -> Result<Self, SliceError>

Select a single index along a dimension, removing that dimension entirely.

This reduces the dimensionality by 1 by “fixing” one coordinate to a specific value. Think of it like taking a cross-section: selecting index 2 from the first dimension of a 3D array gives you a 2D slice, like cutting a plane from a 3D space at a fixed position.

This reduces the dimensionality by 1 by “fixing” one coordinate to a specific value. The fixed coordinate’s contribution (index × stride) gets absorbed into the base offset, while the remaining dimensions keep their original strides unchanged - they still describe the same memory distances between elements.

§Example intuition
  • 3D array → select at(dim=0, index=2) → 2D slice (like a plane)
  • 2D matrix → select at(dim=1, index=3) → 1D vector (like a column)
  • 1D vector → select at(dim=0, index=5) → 0D scalar (single element)
§Arguments
  • dim - The dimension index to select from
  • index - The index within that dimension
§Returns

A new slice with one fewer dimension

§Errors
  • IndexOutOfRange if dim >= self.sizes.len() or index >= self.sizes[dim]
Source

pub fn select( &self, dim: usize, begin: usize, end: usize, step: usize, ) -> Result<Self, SliceError>

A slice defines a strided view; a triple (offset, sizes, strides`). Each coordinate maps to a flat memory index using the formula:

index = offset + ∑ iₖ × strides[k]

where iₖ is the coordinate in dimension k.

The select(dim, range) operation restricts the view to a subrange along a single dimension. It calculates a new slice from a base slice by updating the offset, sizes[dim], and strides[dim] to describe a logically reindexed subregion:

offset       += begin × strides[dim]
sizes[dim]    = ⎡(end - begin) / step⎤
strides[dim] ×= step

This transformation preserves the strided layout and avoids copying data. After select, the view behaves as if indexing starts at zero in the selected dimension, with a new length and stride. From the user’s perspective, nothing changes; indexing remains zero-based, and the resulting shape can be used like any other. The transformation is internal: the view’s offset and stride absorb the selection logic.

Source

pub fn location(&self, coord: &[usize]) -> Result<usize, SliceError>

Return the location of the provided coordinates.

Source

pub fn coordinates(&self, value: usize) -> Result<Vec<usize>, SliceError>

Return the coordinates of the provided value in the n-d space of this Slice.

Source

pub fn len(&self) -> usize

The total length of the slice’s indices.

Source

pub fn is_empty(&self) -> bool

Source

pub fn iter(&self) -> SliceIterator

Iterator over the slice’s indices.

Source

pub fn dim_iter(&self, dims: usize) -> DimSliceIterator

Iterator over sub-dimensions of the slice.

Source

pub fn index(&self, value: usize) -> Result<usize, SliceError>

The linear index formula calculates the logical rank of a multidimensional point in a row-major flattened array, assuming dense gapless storage with zero offset:

    index := Σ(coordinate[i] × ∏(sizes[j] for j > i))

For example, given a 3x2 row-major base array B:

      0 1 2         1
B =   3 4 5    V =  4
      6 7 8         7

Let V be the first column of B. Then,

V      | loc   | index
-------+-------+------
(0, 0) |  1    | 0
(1, 0) |  4    | 1
(2, 0) |  7    | 2
§Conditions Under Which loc = index

The physical offset formula computes the memory location of a point p as:

loc := offset + Σ(coordinate[i] × stride[i])

Let the layout be dense row-major and offset = 0. Then,

stride[i] := ∏(sizes[j] for j > i).

and substituting into the physical offset formula:

  loc = Σ(coordinate[i] × stride[i])
      = Σ(coordinate[i] × ∏(sizes[j] for j > i))
      = index.

Thus, ∀ p = (i, j) ∈ B, loc_B(p) = index_B(p).

§See also

The [get] function performs an inverse operation: given a logical index in row-major order, it computes the physical memory offset according to the slice layout. So, if the layout is row-major then s.get(s.index(loc)) = loc.

Source

pub fn get(&self, index: usize) -> Result<usize, SliceError>

Given a logical index (in row-major order), return the physical memory offset of that element according to this slice’s layout.

The index is interpreted as a position in row-major traversal that is, iterating across columns within rows. This method converts logical row-major index to physical offset by:

  1. Decomposing index into multidimensional coordinates
  2. Computing offset = base + Σ(coordinate[i] × stride[i])

For example, with shape [3, 4] (3 rows, 4 columns) and column-major layout:

sizes  = [3, 4]         // rows, cols
strides = [1, 3]        // column-major: down, then right

Logical matrix:
  A  B  C  D
  E  F  G  H
  I  J  K  L

Memory layout:
offset 0  → [0, 0] = A
offset 1  → [1, 0] = E
offset 2  → [2, 0] = I
offset 3  → [0, 1] = B
offset 4  → [1, 1] = F
offset 5  → [2, 1] = J
offset 6  → [0, 2] = C
offset 7  → [1, 2] = G
offset 8  → [2, 2] = K
offset 9  → [0, 3] = D
offset 10 → [1, 3] = H
offset 11 → [2, 3] = L

Then:
  index = 1  → coordinate [0, 1]  → offset = 0*1 + 1*3 = 3
§Errors

Returns an error if index >= product(sizes).

§See also

The [index] function performs an inverse operation: given a memory offset, it returns the logical position of that element in the slice’s row-major iteration order.

Source

pub fn map<T, F>(&self, mapper: F) -> MapSlice<'_, T, F>
where F: Fn(usize) -> T,

The returned [MapSlice] is a view of this slice, with its elements mapped using the provided mapping function.

Source

pub fn view(&self, new_sizes: &[usize]) -> Result<Slice, SliceError>

Returns a new Slice with the given shape by reinterpreting the layout of this slice.

Constructs a new shape with standard row-major strides, using the same base offset. Returns an error if the reshaped view would access coordinates not valid in the original slice.

§Requirements
  • This slice must be contiguous and have offset == 0.
  • The number of elements must match: self.sizes().iter().product() == new_sizes.iter().product()
  • Each flat offset in the proposed view must be valid in self.
§Errors

Returns SliceError::IncompatibleView if:

  • The element count differs
  • The base offset is nonzero
  • Any offset in the view is not reachable in the original slice
§Example
use ndslice::Slice;
let base = Slice::new_row_major(&[2, 3, 4]);
let reshaped = base.view(&[6, 4]).unwrap();
Source

pub fn subview( &self, starts: &[usize], lens: &[usize], ) -> Result<Slice, SliceError>

Returns a sub-slice of self starting at starts, of size lens.

Source

pub fn enforce_embedding<'a>( &'a self, other: &Slice, ) -> Result<&'a Slice, SliceError>

Ensures that every storage offset used by self is valid in other.

That is, for all p ∈ self: other.coordinates(self.location(p)) is defined.

Returns self on success, enabling fluent chaining.

§Examples
use ndslice::Slice;

let base = Slice::new(0, vec![4, 4], vec![4, 1]).unwrap();
let view = base.subview(&[1, 1], &[2, 2]).unwrap();
assert_eq!(view.enforce_embedding(&base).unwrap().len(), 4);

let small = Slice::new(0, vec![2, 2], vec![2, 1]).unwrap();
assert!(view.enforce_embedding(&small).is_err());

Trait Implementations§

Source§

impl Clone for Slice

Source§

fn clone(&self) -> Slice

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Slice

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for Slice

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Display for Slice

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Hash for Slice

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl IntoIterator for &Slice

Source§

type Item = usize

The type of the elements being iterated over.
Source§

type IntoIter = SliceIterator

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl PartialEq for Slice

Source§

fn eq(&self, other: &Slice) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl ReifySlice for Slice

Source§

fn reify_slice(&self, slice: &Slice) -> Result<Selection, SliceError>

Constructs a Selection expression that symbolically matches all coordinates in the given slice, expressed in the coordinate system of the provided base slice (self).

The result is a nested sequence of range(start..end, step) combinators that match the rectangular region covered by slice in base coordinates. This preserves geometry and layout when slice is layout-aligned — that is, each of its strides is a multiple of the corresponding base stride.

If any dimension is not layout-aligned, the slice is reified by explicitly enumerating its coordinates.

Returns dsl::false_() if the slice is empty.

§Errors

Returns an error if:

  • The base is not contiguous and row-major
  • The slice lies outside the bounds of the base
§Example
use ndslice::selection::ReifySlice;
let shape = ndslice::shape!(x = 4, y = 4);
let base = shape.slice();
let selected = ndslice::select!(shape, x = 1..3, y = 2..4).unwrap();
let slice = selected.slice();
let selection = base.reify_slice(slice).unwrap();
Source§

fn reify_slices<V: AsRef<[Slice]>>( &self, slices: V, ) -> Result<Selection, SliceError>

Converts a list of slices into a symbolic Selection expression over a common base Slice.

Each slice describes a rectangular subregion of the base. This function reifies each slice into a nested range(.., ..) expression in the base coordinate system and returns the union of all such selections.

Empty slices are ignored.

§Errors

Returns an error if any slice:

  • Refers to coordinates not contained within the base
§Example
use ndslice::selection::ReifySlice;

let shape = ndslice::shape!(x = 4, y = 4);
let base = shape.slice();

let a = ndslice::select!(shape, x = 0..2, y = 0..2)
    .unwrap()
    .slice()
    .clone();
let b = ndslice::select!(shape, x = 2..4, y = 2..4)
    .unwrap()
    .slice()
    .clone();

let sel = base.reify_slices(&[a, b]).unwrap();
Source§

impl ReshapeSliceExt for Slice

Source§

fn reshape_with_limit(&self, limit: Limit) -> Slice

Returns a reshaped version of this structure by factoring each dimension into smaller extents no greater than limit, preserving memory layout and flat index semantics. See reshape_with_limit for full behavior and rationale. Read more
Source§

impl Serialize for Slice

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl Eq for Slice

Source§

impl StructuralPartialEq for Slice

Auto Trait Implementations§

§

impl Freeze for Slice

§

impl RefUnwindSafe for Slice

§

impl Send for Slice

§

impl Sync for Slice

§

impl Unpin for Slice

§

impl UnwindSafe for Slice

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,