1use std::cmp::max;
18use std::cmp::min;
19use std::cmp::Ordering;
20
21use num_traits::ToPrimitive;
22
23use crate::spec::function::FunctionRegistry;
24use crate::spec::query::Queryable;
25use crate::ConcreteVariantArray;
26use crate::LocatedNode;
27use crate::NormalizedPath;
28use crate::VariantValue;
29
30#[derive(Debug, PartialEq, Eq, Default, Clone, Copy)]
39pub struct Slice {
40 start: Option<i64>,
45 end: Option<i64>,
50 step: Option<i64>,
54}
55
56impl std::fmt::Display for Slice {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 if let Some(start) = self.start {
59 write!(f, "{start}")?;
60 }
61 write!(f, ":")?;
62 if let Some(end) = self.end {
63 write!(f, "{end}")?;
64 }
65 write!(f, ":")?;
66 if let Some(step) = self.step {
67 write!(f, "{step}")?;
68 }
69 Ok(())
70 }
71}
72
73fn bounds(start: i64, end: i64, step: i64, len: i64) -> (i64, i64) {
75 fn normalize(i: i64, len: i64) -> i64 {
76 if i < 0 {
77 len + i
78 } else {
79 i
80 }
81 }
82
83 let start = normalize(start, len);
84 let end = normalize(end, len);
85
86 if step >= 0 {
87 let lower = min(max(start, 0), len);
88 let upper = min(max(end, 0), len);
89 (lower, upper)
90 } else {
91 let upper = min(max(start, -1), len - 1);
92 let lower = min(max(end, -1), len - 1);
93 (lower, upper)
94 }
95}
96
97impl Slice {
98 pub fn new(start: Option<i64>, end: Option<i64>, step: Option<i64>) -> Self {
100 Self { start, end, step }
101 }
102
103 fn select<'b, T, N, F>(&self, current: &'b T, make_node: F) -> Vec<N>
104 where
105 T: VariantValue,
106 N: 'b,
107 F: Fn(usize, &'b T) -> N,
108 {
109 let vec = match current.as_array() {
110 Some(vec) => vec,
111 None => return vec![],
112 };
113
114 let (start, end, step) = (self.start, self.end, self.step.unwrap_or(1));
115 if step == 0 {
116 return vec![];
119 }
120
121 let len = vec.len().to_i64().unwrap_or(i64::MAX);
122 let (start, end) = if step >= 0 {
123 match (start, end) {
124 (Some(start), Some(end)) => (start, end),
125 (Some(start), None) => (start, len),
126 (None, Some(end)) => (0, end),
127 (None, None) => (0, len),
128 }
129 } else {
130 match (start, end) {
131 (Some(start), Some(end)) => (start, end),
132 (Some(start), None) => (start, -len - 1),
133 (None, Some(end)) => (len - 1, end),
134 (None, None) => (len - 1, -len - 1),
135 }
136 };
137
138 let (lower, upper) = bounds(start, end, step, len);
139 let mut selected = vec![];
140 match step.cmp(&0) {
141 Ordering::Greater => {
142 let mut i = lower;
144 while i < upper {
145 let node = vec.get(i as usize).unwrap();
146 selected.push(make_node(i as usize, node));
147 i += step;
148 }
149 }
150 Ordering::Less => {
151 let mut i = upper;
153 while lower < i {
154 let node = vec.get(i as usize).unwrap();
155 selected.push(make_node(i as usize, node));
156 i += step;
157 }
158 }
159 Ordering::Equal => unreachable!("step is guaranteed not zero here"),
160 }
161 selected
162 }
163}
164
165impl Queryable for Slice {
166 fn query<'b, T: VariantValue, Registry: FunctionRegistry<Value = T>>(
167 &self,
168 current: &'b T,
169 _root: &'b T,
170 _registry: &Registry,
171 ) -> Vec<&'b T> {
172 self.select(current, |_, node| node)
173 }
174
175 fn query_located<'b, T: VariantValue, Registry: FunctionRegistry<Value = T>>(
176 &self,
177 current: &'b T,
178 _root: &'b T,
179 _registry: &Registry,
180 parent: NormalizedPath<'b>,
181 ) -> Vec<LocatedNode<'b, T>> {
182 self.select(current, |i, node| {
183 LocatedNode::new(parent.clone_and_push(i), node)
184 })
185 }
186}