ps_util/
array.rs

1use std::fmt::Write;
2
3use crate::{subarray, subarray_checked, subarray_unchecked};
4
5pub trait Array<T> {
6    /// Returns a reference to the element at the specified index,
7    /// or `None` if the index is out of bounds.
8    ///
9    /// # Examples
10    ///
11    /// ```
12    /// use ps_util::Array;
13    /// let arr = [1, 2, 3];
14    /// assert_eq!(arr.at(0), Some(&1));
15    /// assert_eq!(arr.at(5), None);
16    /// ```
17    fn at(&self, index: usize) -> Option<&T>;
18
19    /// Concatenates this array with another slice and returns a new vector.
20    ///
21    /// # Examples
22    ///
23    /// ```
24    /// use ps_util::Array;
25    /// let arr = [1, 2];
26    /// let result = arr.concat(&[3, 4]);
27    /// assert_eq!(result, vec![1, 2, 3, 4]);
28    /// ```
29    fn concat(&self, other: impl AsRef<[T]>) -> Vec<T>
30    where
31        T: Clone;
32
33    /// Returns an iterator of (index, &T) tuples for each element.
34    ///
35    /// # Examples
36    ///
37    /// ```
38    /// use ps_util::Array;
39    /// let arr = ['a', 'b'];
40    /// let entries: Vec<_> = arr.entries().collect();
41    /// assert_eq!(entries, vec![(0, &'a'), (1, &'b')]);
42    /// ```
43    fn entries<'a>(&'a self) -> impl Iterator<Item = (usize, &'a T)>
44    where
45        T: 'a;
46
47    /// Tests whether all elements match the predicate.
48    ///
49    /// Returns `true` if the predicate returns `true` for every element,
50    /// or if the array is empty.
51    ///
52    /// # Examples
53    ///
54    /// ```
55    /// use ps_util::Array;
56    /// let arr = [2, 4, 6];
57    /// assert!(arr.every(|x| x % 2 == 0));
58    /// assert!(!arr.every(|x| x > &5));
59    /// ```
60    fn every(&self, predicate: impl FnMut(&T) -> bool) -> bool;
61
62    /// Returns a reference to the first element that matches the predicate.
63    ///
64    /// # Examples
65    ///
66    /// ```
67    /// use ps_util::Array;
68    /// let arr = [1, 2, 3, 4];
69    /// assert_eq!(arr.find(|x| x > &2), Some(&3));
70    /// assert_eq!(arr.find(|x| x > &10), None);
71    /// ```
72    fn find(&self, predicate: impl FnMut(&T) -> bool) -> Option<&T>;
73
74    /// Returns the index of the first element that matches the predicate.
75    ///
76    /// # Examples
77    ///
78    /// ```
79    /// use ps_util::Array;
80    /// let arr = [1, 2, 3, 4];
81    /// assert_eq!(arr.find_index(|x| x > &2), Some(2));
82    /// assert_eq!(arr.find_index(|x| x > &10), None);
83    /// ```
84    fn find_index(&self, predicate: impl FnMut(&T) -> bool) -> Option<usize>;
85
86    /// Returns a reference to the last element that matches the predicate.
87    ///
88    /// # Examples
89    ///
90    /// ```
91    /// use ps_util::Array;
92    /// let arr = [1, 2, 3, 4];
93    /// assert_eq!(arr.find_last(|x| x < &4), Some(&3));
94    /// assert_eq!(arr.find_last(|x| x > &10), None);
95    /// ```
96    fn find_last(&self, predicate: impl FnMut(&T) -> bool) -> Option<&T>;
97
98    /// Returns the index of the last element that matches the predicate.
99    ///
100    /// # Examples
101    ///
102    /// ```
103    /// use ps_util::Array;
104    /// let arr = [1, 2, 3, 4];
105    /// assert_eq!(arr.find_last_index(|x| x < &4), Some(2));
106    /// assert_eq!(arr.find_last_index(|x| x > &10), None);
107    /// ```
108    fn find_last_index(&self, predicate: impl FnMut(&T) -> bool) -> Option<usize>;
109
110    /// Returns a vector containing all elements that match the predicate.
111    ///
112    /// # Examples
113    ///
114    /// ```
115    /// use ps_util::Array;
116    /// let arr = [1, 2, 3, 4];
117    /// assert_eq!(arr.filter(|x| x % 2 == 0), vec![2, 4]);
118    /// ```
119    fn filter(&self, predicate: impl FnMut(&T) -> bool) -> Vec<T>
120    where
121        T: Clone;
122
123    /// Flattens a level of nesting in an array of iterables.
124    ///
125    /// # Examples
126    ///
127    /// ```
128    /// use ps_util::Array;
129    /// let arr = [vec![1, 2], vec![3, 4]];
130    /// assert_eq!(arr.flat(), vec![1, 2, 3, 4]);
131    /// ```
132    fn flat(&self) -> Vec<T::Item>
133    where
134        T: Clone + IntoIterator;
135
136    /// Maps each element to an iterable and flattens the result.
137    ///
138    /// # Examples
139    ///
140    /// ```
141    /// use ps_util::Array;
142    /// let arr = [1, 2, 3];
143    /// let result = arr.flat_map(|x| vec![*x, *x * 2]);
144    /// assert_eq!(result, vec![1, 2, 2, 4, 3, 6]);
145    /// ```
146    fn flat_map<O, I>(&self, mapper: impl FnMut(&T) -> I) -> Vec<O>
147    where
148        I: IntoIterator<Item = O>;
149
150    /// Applies a closure to each element for side effects.
151    ///
152    /// # Examples
153    ///
154    /// ```
155    /// use ps_util::Array;
156    /// let arr = [1, 2, 3];
157    /// arr.for_each(|x| println!("{}", x));
158    /// ```
159    fn for_each(&self, cb: impl FnMut(&T));
160
161    /// Checks whether the array contains the specified value.
162    ///
163    /// # Examples
164    ///
165    /// ```
166    /// use ps_util::Array;
167    /// let arr = [1, 2, 3];
168    /// assert!(arr.includes(&2));
169    /// assert!(!arr.includes(&5));
170    /// ```
171    fn includes(&self, value: &T) -> bool
172    where
173        T: PartialEq;
174
175    /// Returns the index of the first occurrence of the specified value,
176    /// or `None` if not found.
177    ///
178    /// # Examples
179    ///
180    /// ```
181    /// use ps_util::Array;
182    /// let arr = [1, 2, 3, 2];
183    /// assert_eq!(arr.index_of(&2), Some(1));
184    /// assert_eq!(arr.index_of(&5), None);
185    /// ```
186    fn index_of(&self, value: &T) -> Option<usize>
187    where
188        T: PartialEq;
189
190    /// Returns `true` if the array is empty.
191    ///
192    /// # Examples
193    ///
194    /// ```
195    /// use ps_util::Array;
196    /// assert!(Vec::<i32>::new().is_empty());
197    /// assert!(![1].is_empty());
198    /// ```
199    fn is_empty(&self) -> bool;
200
201    /// Concatenates all elements into a string, separated by the given separator.
202    ///
203    /// # Errors
204    ///
205    /// Errors are passed from the [`std::fmt::Display`] implementation.
206    ///
207    /// # Examples
208    ///
209    /// ```
210    /// use ps_util::Array;
211    /// let arr = [1, 2, 3];
212    /// assert_eq!(arr.join(", ").unwrap(), "1, 2, 3");
213    /// ```
214    fn join(&self, separator: &str) -> Result<String, std::fmt::Error>
215    where
216        T: std::fmt::Display;
217
218    /// Returns an iterator of indices (0, 1, 2, ...).
219    ///
220    /// # Examples
221    ///
222    /// ```
223    /// use ps_util::Array;
224    /// let arr = ['a', 'b', 'c'];
225    /// let keys: Vec<_> = arr.keys().collect();
226    /// assert_eq!(keys, vec![0, 1, 2]);
227    /// ```
228    fn keys(&self) -> impl Iterator<Item = usize>;
229
230    /// Returns the index of the last occurrence of the specified value,
231    /// or `None` if not found.
232    ///
233    /// # Examples
234    ///
235    /// ```
236    /// use ps_util::Array;
237    /// let arr = [1, 2, 3, 2];
238    /// assert_eq!(arr.last_index_of(&2), Some(3));
239    /// assert_eq!(arr.last_index_of(&5), None);
240    /// ```
241    fn last_index_of(&self, value: &T) -> Option<usize>
242    where
243        T: PartialEq;
244
245    /// Returns the number of elements in the array.
246    ///
247    /// # Examples
248    ///
249    /// ```
250    /// use ps_util::Array;
251    /// let arr = [1, 2, 3];
252    /// assert_eq!(arr.len(), 3);
253    /// ```
254    fn len(&self) -> usize;
255
256    /// Transforms each element using the provided mapper function
257    /// and returns a vector of the results.
258    ///
259    /// # Examples
260    ///
261    /// ```
262    /// use ps_util::Array;
263    /// let arr = [1, 2, 3u8];
264    /// assert_eq!(arr.as_slice().map(|x| x * 2), vec![2, 4, 6]);
265    /// ```
266    fn map<O>(&self, mapper: impl FnMut(&T) -> O) -> Vec<O>;
267
268    /// Reduces the array to a single value by applying a callback
269    /// with an accumulator, starting from the left.
270    ///
271    /// # Examples
272    ///
273    /// ```
274    /// use ps_util::Array;
275    /// let arr = [1, 2, 3, 4];
276    /// let sum = arr.reduce(|acc, x| acc + x, 0);
277    /// assert_eq!(sum, 10);
278    /// ```
279    fn reduce<O>(&self, reducer: impl FnMut(O, &T) -> O, initial: O) -> O;
280
281    /// Reduces the array to a single value by applying a callback
282    /// with an accumulator, starting from the right.
283    ///
284    /// # Examples
285    ///
286    /// ```
287    /// use ps_util::Array;
288    /// let arr = [1, 2, 3];
289    /// let result = arr.reduce_right(
290    ///     |acc, x| format!("{}{}", acc, x),
291    ///     String::new()
292    /// );
293    /// assert_eq!(result, "321");
294    /// ```
295    fn reduce_right<O>(&self, reducer: impl FnMut(O, &T) -> O, initial: O) -> O;
296
297    /// Returns a slice of the array from `start` to `end` (exclusive).
298    ///
299    /// If `end` is `None`, slices to the end of the array. Indices are clamped
300    /// to valid bounds; if `start` exceeds the array length, an empty slice
301    /// is returned.
302    ///
303    /// # Examples
304    ///
305    /// ```
306    /// use ps_util::Array;
307    /// let arr = [1, 2, 3, 4];
308    /// assert_eq!(arr.slice(1, Some(3)), &[2, 3][..]);
309    /// assert_eq!(arr.slice(2, None), &[3, 4][..]);
310    /// assert_eq!(arr.slice(10, Some(20)), &[][..]);
311    /// ```
312    fn slice(&self, start: usize, end: Option<usize>) -> &[T];
313
314    /// Tests whether any element matches the predicate.
315    ///
316    /// Returns `true` if the predicate returns `true` for at least one element.
317    ///
318    /// # Examples
319    ///
320    /// ```
321    /// use ps_util::Array;
322    /// let arr = [1, 2, 3];
323    /// assert!(arr.some(|x| x > &2));
324    /// assert!(!arr.some(|x| x > &10));
325    /// ```
326    fn some(&self, predicate: impl FnMut(&T) -> bool) -> bool;
327
328    /// Returns a fixed-size array reference starting at the given index.
329    ///
330    /// # Panics
331    ///
332    /// Panics if there are not enough elements remaining in the array.
333    ///
334    /// # Examples
335    ///
336    /// ```
337    /// use ps_util::Array;
338    /// let arr = [1, 2, 3, 4];
339    /// assert_eq!(arr.subarray::<2>(1), &[2, 3]);
340    /// ```
341    fn subarray<const S: usize>(&self, index: usize) -> &[T; S];
342
343    /// Checked version of `subarray`. Returns `None` if bounds are exceeded.
344    ///
345    /// # Examples
346    ///
347    /// ```
348    /// use ps_util::Array;
349    /// let arr = [1, 2, 3];
350    /// assert_eq!(arr.subarray_checked::<2>(1), Some(&[2, 3]));
351    /// assert_eq!(arr.subarray_checked::<2>(2), None);
352    /// ```
353    fn subarray_checked<const S: usize>(&self, index: usize) -> Option<&[T; S]>;
354
355    /// Unchecked version of `subarray`. Undefined behavior if bounds are exceeded.
356    ///
357    /// # Safety
358    ///
359    /// Caller must ensure that `index + S <= self.len()`.
360    ///
361    /// # Examples
362    ///
363    /// ```
364    /// use ps_util::Array;
365    /// let arr = [1, 2, 3, 4];
366    /// unsafe {
367    ///     assert_eq!(arr.subarray_unchecked::<2>(1), &[2, 3]);
368    /// }
369    /// ```
370    unsafe fn subarray_unchecked<const S: usize>(&self, index: usize) -> &[T; S];
371
372    /// Returns an iterator over references to the elements.
373    ///
374    /// # Examples
375    ///
376    /// ```
377    /// use ps_util::Array;
378    /// let arr = [1, 2, 3];
379    /// let values: Vec<_> = arr.values().collect();
380    /// assert_eq!(values, vec![&1, &2, &3]);
381    /// ```
382    fn values<'a>(&'a self) -> impl Iterator<Item = &'a T>
383    where
384        T: 'a;
385}
386
387impl<A, T> Array<T> for A
388where
389    A: AsRef<[T]>,
390{
391    fn at(&self, index: usize) -> Option<&T> {
392        self.as_ref().get(index)
393    }
394
395    fn concat(&self, other: impl AsRef<[T]>) -> Vec<T>
396    where
397        T: Clone,
398    {
399        let lhs = self.as_ref();
400        let rhs = other.as_ref();
401
402        let mut concatenated = Vec::with_capacity(lhs.len() + rhs.len());
403
404        concatenated.extend_from_slice(lhs);
405        concatenated.extend_from_slice(rhs);
406
407        concatenated
408    }
409
410    fn entries<'a>(&'a self) -> impl Iterator<Item = (usize, &'a T)>
411    where
412        T: 'a,
413    {
414        self.as_ref().iter().enumerate()
415    }
416
417    fn every(&self, predicate: impl FnMut(&T) -> bool) -> bool {
418        self.as_ref().iter().all(predicate)
419    }
420
421    fn filter(&self, mut predicate: impl FnMut(&T) -> bool) -> Vec<T>
422    where
423        T: Clone,
424    {
425        self.as_ref()
426            .iter()
427            .filter(|item| predicate(item))
428            .cloned()
429            .collect()
430    }
431
432    fn find(&self, mut predicate: impl FnMut(&T) -> bool) -> Option<&T> {
433        Iterator::find(&mut self.as_ref().iter(), |item| predicate(item))
434    }
435
436    fn find_index(&self, predicate: impl FnMut(&T) -> bool) -> Option<usize> {
437        self.as_ref().iter().position(predicate)
438    }
439
440    fn find_last(&self, mut predicate: impl FnMut(&T) -> bool) -> Option<&T> {
441        self.as_ref().iter().rfind(|item| predicate(item))
442    }
443
444    fn find_last_index(&self, predicate: impl FnMut(&T) -> bool) -> Option<usize> {
445        self.as_ref().iter().rposition(predicate)
446    }
447
448    fn flat(&self) -> Vec<<T>::Item>
449    where
450        T: Clone + IntoIterator,
451    {
452        self.as_ref().iter().cloned().flatten().collect()
453    }
454
455    fn flat_map<O, I>(&self, mapper: impl FnMut(&T) -> I) -> Vec<O>
456    where
457        I: IntoIterator<Item = O>,
458    {
459        self.as_ref().iter().flat_map(mapper).collect()
460    }
461
462    fn for_each(&self, cb: impl FnMut(&T)) {
463        self.as_ref().iter().for_each(cb);
464    }
465
466    fn includes(&self, value: &T) -> bool
467    where
468        T: PartialEq,
469    {
470        self.as_ref().contains(value)
471    }
472
473    fn index_of(&self, value: &T) -> Option<usize>
474    where
475        T: PartialEq,
476    {
477        self.as_ref().iter().position(|x| x == value)
478    }
479
480    fn is_empty(&self) -> bool {
481        self.as_ref().is_empty()
482    }
483
484    fn join(&self, separator: &str) -> Result<String, std::fmt::Error>
485    where
486        T: std::fmt::Display,
487    {
488        let mut a = String::new();
489        let mut iterator = self.as_ref().iter();
490
491        if let Some(first) = iterator.next() {
492            write!(&mut a, "{first}")?;
493
494            for item in iterator {
495                write!(&mut a, "{separator}{item}")?;
496            }
497        }
498
499        Ok(a)
500    }
501
502    fn keys(&self) -> impl Iterator<Item = usize> {
503        0..self.as_ref().len()
504    }
505
506    fn last_index_of(&self, value: &T) -> Option<usize>
507    where
508        T: PartialEq,
509    {
510        self.find_last_index(|item| item == value)
511    }
512
513    fn len(&self) -> usize {
514        self.as_ref().len()
515    }
516
517    fn map<O>(&self, mapper: impl FnMut(&T) -> O) -> Vec<O> {
518        self.as_ref().iter().map(mapper).collect()
519    }
520
521    fn reduce<O>(&self, reducer: impl FnMut(O, &T) -> O, initial: O) -> O {
522        self.as_ref().iter().fold(initial, reducer)
523    }
524
525    fn reduce_right<O>(&self, reducer: impl FnMut(O, &T) -> O, initial: O) -> O {
526        self.as_ref().iter().rev().fold(initial, reducer)
527    }
528
529    fn slice(&self, start: usize, end: Option<usize>) -> &[T] {
530        let full = self.as_ref();
531        let len = full.len();
532        let start = usize::min(start, len);
533        let end = end.unwrap_or(len).clamp(start, len);
534
535        &full[start..end]
536    }
537
538    fn some(&self, predicate: impl FnMut(&T) -> bool) -> bool {
539        self.as_ref().iter().any(predicate)
540    }
541
542    fn subarray<const S: usize>(&self, index: usize) -> &[T; S] {
543        subarray(self.as_ref(), index)
544    }
545
546    fn subarray_checked<const S: usize>(&self, index: usize) -> Option<&[T; S]> {
547        subarray_checked(self.as_ref(), index)
548    }
549
550    unsafe fn subarray_unchecked<const S: usize>(&self, index: usize) -> &[T; S] {
551        subarray_unchecked(self.as_ref(), index)
552    }
553
554    fn values<'a>(&'a self) -> impl Iterator<Item = &'a T>
555    where
556        T: 'a,
557    {
558        self.as_ref().iter()
559    }
560}