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