ferray_core/indexing/mod.rs
1// ferray-core: Indexing module (REQ-12 through REQ-15a)
2//
3// Provides basic indexing (integer + slice → views), advanced indexing
4// (fancy + boolean → copies), and extended indexing functions (take, put,
5// choose, compress, etc.).
6
7pub mod advanced;
8pub mod basic;
9pub mod extended;
10
11// Flat re-exports of the most NumPy-namespace-adjacent extended
12// indexing functions so users don't need to reach into the `extended`
13// submodule for the common cases. Matches NumPy's flat top-level
14// namespace (`np.ravel_multi_index`, `np.unravel_index`, `np.nonzero`,
15// `np.argwhere`, `np.flatnonzero`).
16pub use extended::{
17 MaskKind, argwhere, extract, flatnonzero, mask_indices, nonzero, place, putmask,
18 ravel_multi_index, unravel_index,
19};
20
21use crate::error::{FerrayError, FerrayResult};
22
23/// Normalize a (possibly negative) index into a non-negative `usize`
24/// suitable for array access along `axis`. Negative indices count from the
25/// end (`-1` is the last element, etc.). Returns `IndexOutOfBounds` when
26/// the normalized index falls outside `[0, size)`.
27///
28/// Shared by all three indexing submodules; see issue #121 for the
29/// original triplication.
30#[inline]
31pub(crate) const fn normalize_index(index: isize, size: usize, axis: usize) -> FerrayResult<usize> {
32 if index < 0 {
33 let pos = size as isize + index;
34 if pos < 0 {
35 return Err(FerrayError::index_out_of_bounds(index, axis, size));
36 }
37 Ok(pos as usize)
38 } else {
39 let idx = index as usize;
40 if idx >= size {
41 return Err(FerrayError::index_out_of_bounds(index, axis, size));
42 }
43 Ok(idx)
44 }
45}