1use thiserror::Error;
2
3#[derive(Debug, Clone, PartialEq, Eq, Error)]
5pub enum AxisError {
6 #[error("axis {axis} is out of bounds for rank {rank}")]
8 OutOfBounds { axis: isize, rank: usize },
9 #[error("duplicate axis {axis}")]
11 Duplicate { axis: usize },
12}
13
14pub fn normalize_axis(axis: isize, rank: usize) -> Result<usize, AxisError> {
25 let normalized = if axis >= 0 {
26 axis as usize
27 } else {
28 rank.checked_sub(axis.unsigned_abs())
29 .ok_or(AxisError::OutOfBounds { axis, rank })?
30 };
31 if normalized >= rank {
32 return Err(AxisError::OutOfBounds { axis, rank });
33 }
34 Ok(normalized)
35}
36
37pub fn normalize_axes(axes: &[isize], rank: usize) -> Result<Vec<usize>, AxisError> {
48 let mut out = Vec::with_capacity(axes.len());
49 let mut seen = vec![false; rank];
50 for &axis in axes {
51 let normalized = normalize_axis(axis, rank)?;
52 if seen[normalized] {
53 return Err(AxisError::Duplicate { axis: normalized });
54 }
55 seen[normalized] = true;
56 out.push(normalized);
57 }
58 Ok(out)
59}