ctoolbox/formats/eite/util/
array.rs1pub fn arr_empty<T>(a: &[T]) -> bool {
2 a.is_empty()
3}
4pub fn arr_nonempty<T>(a: &[T]) -> bool {
5 !a.is_empty()
6}
7
8pub fn arr_eq<T: PartialEq>(a: &[T], b: &[T]) -> bool {
9 if a.len() != b.len() {
10 return false;
11 }
12 a.iter().zip(b).all(|(x, y)| x == y)
13}
14
15pub fn count<T>(a: &[T]) -> usize {
17 a.len()
18}
19
20pub fn append_vec<T: Clone>(a: &[T], b: &[T]) -> Vec<T> {
25 let mut out = Vec::with_capacity(a.len() + b.len());
26 out.extend_from_slice(a);
27 out.extend_from_slice(b);
28 out
29}
30
31pub fn js_compat_array_slice<T: Clone>(
32 a: &[T],
33 start: i64,
34 end_exclusive: i64,
35) -> Option<Vec<T>> {
36 let len = i64::try_from(a.len()).expect("usize not fit in i64");
37
38 let mut s = if start < 0 { len + start } else { start };
40 let mut e = if end_exclusive < 0 {
41 len + end_exclusive
42 } else {
43 end_exclusive
44 };
45
46 if s < 0 {
48 s = 0;
49 }
50 if e < 0 {
51 e = 0;
52 }
53 if s > len {
54 s = len;
55 }
56 if e > len {
57 e = len;
58 }
59
60 if e <= s {
62 return None;
63 }
64
65 let s = usize::try_from(s).ok()?;
66 let e = usize::try_from(e).ok()?;
67 let slice = a.get(s..e)?;
68
69 Some(slice.to_vec())
70}
71
72pub fn subset<T: Clone>(
74 a: &[T],
75 mut start: i64,
76 mut end: i64,
77) -> Option<Vec<T>> {
78 let mut count = i64::try_from(a.len()).expect("usize not fit in i64");
79
80 if start < 0 {
81 start += count;
82 }
83 if end < 0 {
84 end += count;
85 }
86
87 count = end;
110 let mut res: Vec<T> = Vec::new();
111
112 let mut i = i128::from(start);
113 let count_i128 = i128::from(count);
114 while i <= count_i128 {
115 if let Some(item) = a.get(usize::try_from(i).ok()?) {
116 res.push(item.clone());
117 } else {
118 return None;
119 }
120 i += 1;
121 }
122
123 Some(res)
124}
125
126pub fn pop<T: Clone>(a: &[T]) -> Vec<T> {
129 if a.is_empty() {
130 Vec::new()
131 } else {
132 a[..a.len() - 1].to_vec()
133 }
134}
135
136pub fn shift<T: Clone>(a: &[T]) -> Vec<T> {
138 if a.len() <= 1 {
139 Vec::new()
140 } else {
141 a[1..].to_vec()
142 }
143}
144
145pub fn first<T: Clone>(a: &[T]) -> Option<T> {
147 a.first().cloned()
148}
149
150pub fn last<T: Clone>(a: &[T]) -> Option<T> {
152 a.last().cloned()
153}
154
155pub fn set_element<T: Clone>(a: &mut Vec<T>, index: isize, value: T) {
159 let len = isize::try_from(a.len()).expect("usize not fit in isize");
160 let mut idx = index;
161 if idx < 0 {
162 idx += len;
163 }
164 assert!(
165 !(idx < 0 || idx > len),
166 "Cannot insert at position {index} greater than appending to the length of the array."
167 );
168 if idx == len {
169 a.push(value);
170 } else {
171 a[usize::try_from(idx).expect("isize not fit in usize")] = value;
172 }
173}
174
175fn normalize_bounds(len: usize, start: isize, end: isize) -> (usize, usize) {
181 let l = isize::try_from(len).expect("usize not fit in isize");
182 let s = if start < 0 { l + start } else { start };
183 let e = if end < 0 { l + end } else { end };
184 let s = s.clamp(0, l.max(0));
185 let e = e.clamp(0, l.max(0));
186 (
187 usize::try_from(s).expect("isize not fit in usize"),
188 usize::try_from(e).expect("isize not fit in usize"),
189 )
190}
191
192pub fn slice_inclusive_bool(a: &[bool], start: isize, end: isize) -> Vec<bool> {
193 if a.is_empty() {
194 return Vec::new();
195 }
196 let (s, e) = normalize_bounds(a.len(), start, end);
197 if e < s {
198 return Vec::new();
199 }
200 a[s..=e.min(a.len() - 1)].to_vec()
201}
202
203pub fn slice_inclusive_i32(a: &[i32], start: isize, end: isize) -> Vec<i32> {
204 if a.is_empty() {
205 return Vec::new();
206 }
207 let (s, e) = normalize_bounds(a.len(), start, end);
208 if e < s {
209 return Vec::new();
210 }
211 a[s..=e.min(a.len() - 1)].to_vec()
212}
213
214pub fn slice_inclusive_string(
215 a: &[String],
216 start: isize,
217 end: isize,
218) -> Vec<String> {
219 if a.is_empty() {
220 return Vec::new();
221 }
222 let (s, e) = normalize_bounds(a.len(), start, end);
223 if e < s {
224 return Vec::new();
225 }
226 a[s..=e.min(a.len() - 1)].to_vec()
227}
228
229pub fn one_bool(b: bool) -> Vec<bool> {
231 vec![b]
232}
233pub fn one_i32(n: i32) -> Vec<i32> {
234 vec![n]
235}
236pub fn one_string(s: impl Into<String>) -> Vec<String> {
237 vec![s.into()]
238}
239
240pub fn contains<T: PartialEq>(a: &[T], needle: &T) -> bool {
244 a.iter().any(|v| v == needle)
245}
246
247pub fn index_of<T: PartialEq>(a: &[T], needle: &T) -> isize {
248 for (i, v) in a.iter().enumerate() {
249 if v == needle {
250 return isize::try_from(i).expect("usize not fit in isize");
251 }
252 }
253 -1
254}
255
256pub fn str_print_arr<T: ToString>(arr: &[T]) -> String {
261 arr.iter()
262 .map(std::string::ToString::to_string)
263 .collect::<Vec<_>>()
264 .join(" ")
265}
266
267pub fn print_array<T: ToString>(arr: &[T]) -> String {
269 str_print_arr(arr)
270}
271
272pub fn str_print_array<T: ToString>(arr: &[T]) -> String {
274 str_print_arr(arr)
275}
276
277pub fn print_arr<T: ToString>(arr: &[T]) -> String {
279 str_print_arr(arr)
280}
281
282pub fn sum_array(a: &[i32]) -> i32 {
287 a.iter().copied().sum()
288}
289
290#[cfg(test)]
291mod tests {
292 use super::*;
293
294 #[crate::ctb_test]
295 fn test_slice_inclusive() {
296 let v = vec![1, 2, 3, 4, 5];
297 assert_eq!(slice_inclusive_i32(&v, 1, 3), vec![2, 3, 4]);
298 assert_eq!(slice_inclusive_i32(&v, -3, -1), vec![3, 4, 5]);
299 assert_eq!(slice_inclusive_i32(&v, 0, 0), vec![1]);
300 }
301
302 #[crate::ctb_test]
303 fn test_contains() {
304 let v = vec![String::from("a"), String::from("b")];
305 assert!(contains(&v, &"a".to_string()));
306 assert!(!contains(&v, &"c".to_string()));
307 }
308
309 #[crate::ctb_test]
312 fn test_index_of() {
313 let v = vec![1, 2, 3];
314 assert_eq!(index_of(&v, &2), 1);
315 assert_eq!(index_of(&v, &4), -1);
316 }
317
318 #[crate::ctb_test]
319 fn test_arr_eq() {
320 assert!(arr_eq(&[1, 2, 3], &[1, 2, 3]));
321 assert!(!arr_eq(&[1, 2], &[1, 2, 3]));
322 }
323
324 #[crate::ctb_test]
325 fn test_sum_array() {
326 assert_eq!(sum_array(&[1, 2, 3, 4]), 10);
327 }
328}