1use rlx_ir::Dim;
7
8use crate::Tensor;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum SliceAxis {
16 All,
17 Index(i64),
18 Range { start: i64, end: i64 },
19 From(i64),
20}
21
22#[inline]
24pub fn ax() -> SliceAxis {
25 SliceAxis::All
26}
27
28#[inline]
31pub fn ix(i: i64) -> SliceAxis {
32 SliceAxis::Index(i)
33}
34
35#[inline]
37pub fn rg(start: i64, end: i64) -> SliceAxis {
38 SliceAxis::Range { start, end }
39}
40
41#[inline]
43pub fn tail(start: i64) -> SliceAxis {
44 SliceAxis::From(start)
45}
46
47pub(crate) fn resolve_index(idx: i64, dim: Option<usize>, axis: usize) -> usize {
50 if idx >= 0 {
51 return idx as usize;
52 }
53 let n = dim
54 .unwrap_or_else(|| panic!("negative index requires a static dimension on axis {axis}"))
55 as i64;
56 let resolved = n + idx;
57 assert!(
58 resolved >= 0,
59 "index {idx} out of bounds for axis {axis} of size {n}"
60 );
61 resolved as usize
62}
63
64#[derive(Debug, Clone, Default)]
66pub struct SliceSpec {
67 axes: Vec<SliceAxis>,
68}
69
70impl SliceSpec {
71 pub fn new(axes: Vec<SliceAxis>) -> Self {
72 Self { axes }
73 }
74
75 pub fn apply(&self, tensor: &Tensor) -> Tensor {
77 let mut out = tensor.clone();
78 let shape = tensor.shape();
79 for (axis, spec) in self.axes.iter().enumerate() {
80 let dim = match shape.dims().get(axis) {
81 Some(Dim::Static(n)) => Some(*n),
82 Some(Dim::Dynamic(_)) => None,
83 None => panic!("slice axis {axis} out of bounds (rank {})", shape.rank()),
84 };
85 out = match spec {
86 SliceAxis::All => out,
87 SliceAxis::Index(i) => out.narrow(axis, resolve_index(*i, dim, axis), 1),
88 SliceAxis::Range { start, end } => {
89 let s = resolve_index(*start, dim, axis);
90 let e = resolve_index(*end, dim, axis);
91 assert!(e > s, "slice range end must exceed start (axis {axis})");
92 out.narrow(axis, s, e - s)
93 }
94 SliceAxis::From(start) => {
95 let s = resolve_index(*start, dim, axis);
96 let n = dim.unwrap_or_else(|| {
97 panic!("slice `start..` requires a static dimension on axis {axis}")
98 });
99 out.narrow(axis, s, n - s)
100 }
101 };
102 }
103 out
104 }
105}
106
107#[macro_export]
119macro_rules! s {
120 ( $( $axis:expr ),* $(,)? ) => {
121 $crate::SliceSpec::new(vec![ $( $axis ),* ])
122 };
123}