graphitepdf_utils/
array.rs1#[derive(Clone, Debug, PartialEq, Eq)]
2pub enum OneOrMany<T> {
3 One(T),
4 Many(Vec<T>),
5}
6
7impl<T> From<T> for OneOrMany<T> {
8 fn from(value: T) -> Self {
9 Self::One(value)
10 }
11}
12
13impl<T> From<Vec<T>> for OneOrMany<T> {
14 fn from(value: Vec<T>) -> Self {
15 Self::Many(value)
16 }
17}
18
19pub fn cast_array<T>(input: impl Into<OneOrMany<T>>) -> Vec<T> {
20 match input.into() {
21 OneOrMany::One(value) => vec![value],
22 OneOrMany::Many(values) => values,
23 }
24}
25
26pub fn adjust<T, F>(index: isize, mut adjuster: F, values: &[T]) -> Vec<T>
27where
28 T: Clone,
29 F: FnMut(T) -> T,
30{
31 let mut result = values.to_vec();
32 let len = result.len();
33
34 if let Some(index) = normalize_index(index, len) {
35 result[index] = adjuster(result[index].clone());
36 }
37
38 result
39}
40
41pub trait DropLast {
42 type Output;
43
44 fn drop_last(self) -> Self::Output;
45}
46
47pub fn drop_last<T>(value: T) -> T::Output
48where
49 T: DropLast,
50{
51 value.drop_last()
52}
53
54impl<T: Clone> DropLast for &[T] {
55 type Output = Vec<T>;
56
57 fn drop_last(self) -> Self::Output {
58 self[..self.len().saturating_sub(1)].to_vec()
59 }
60}
61
62impl<T> DropLast for Vec<T> {
63 type Output = Vec<T>;
64
65 fn drop_last(mut self) -> Self::Output {
66 let _ = self.pop();
67 self
68 }
69}
70
71impl DropLast for &str {
72 type Output = String;
73
74 fn drop_last(self) -> Self::Output {
75 let mut result = self.to_string();
76 let _ = result.pop();
77 result
78 }
79}
80
81impl DropLast for String {
82 type Output = String;
83
84 fn drop_last(mut self) -> Self::Output {
85 let _ = self.pop();
86 self
87 }
88}
89
90pub trait Last {
91 type Output;
92
93 fn last_value(self) -> Option<Self::Output>;
94}
95
96pub fn last<T>(value: T) -> Option<T::Output>
97where
98 T: Last,
99{
100 value.last_value()
101}
102
103impl<T: Clone> Last for &[T] {
104 type Output = T;
105
106 fn last_value(self) -> Option<Self::Output> {
107 self.last().cloned()
108 }
109}
110
111impl<T> Last for Vec<T> {
112 type Output = T;
113
114 fn last_value(self) -> Option<Self::Output> {
115 self.into_iter().last()
116 }
117}
118
119impl Last for &str {
120 type Output = char;
121
122 fn last_value(self) -> Option<Self::Output> {
123 self.chars().next_back()
124 }
125}
126
127impl Last for String {
128 type Output = char;
129
130 fn last_value(self) -> Option<Self::Output> {
131 self.chars().next_back()
132 }
133}
134
135pub fn repeat<T>(value: T, count: usize) -> Vec<T>
136where
137 T: Clone,
138{
139 vec![value; count]
140}
141
142pub trait Reverse {
143 type Output;
144
145 fn reverse_value(self) -> Self::Output;
146}
147
148pub fn reverse<T>(value: T) -> T::Output
149where
150 T: Reverse,
151{
152 value.reverse_value()
153}
154
155impl<T: Clone> Reverse for &[T] {
156 type Output = Vec<T>;
157
158 fn reverse_value(self) -> Self::Output {
159 self.iter().cloned().rev().collect()
160 }
161}
162
163impl<T> Reverse for Vec<T> {
164 type Output = Vec<T>;
165
166 fn reverse_value(mut self) -> Self::Output {
167 self.reverse();
168 self
169 }
170}
171
172pub fn without<T>(excluded: &[T], values: &[T]) -> Vec<T>
173where
174 T: Clone + PartialEq,
175{
176 values
177 .iter()
178 .filter(|value| !excluded.iter().any(|excluded| excluded == *value))
179 .cloned()
180 .collect()
181}
182
183fn normalize_index(index: isize, len: usize) -> Option<usize> {
184 if len == 0 {
185 return None;
186 }
187
188 if index >= 0 {
189 let index = usize::try_from(index).ok()?;
190 return (index < len).then_some(index);
191 }
192
193 let len = isize::try_from(len).ok()?;
194 let adjusted = len.checked_add(index)?;
195
196 if adjusted < 0 {
197 None
198 } else {
199 usize::try_from(adjusted).ok()
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206
207 #[test]
208 fn casts_single_values_and_vectors() {
209 assert_eq!(cast_array("foo"), vec!["foo"]);
210 assert_eq!(cast_array::<&str>(vec!["foo"]), vec!["foo"]);
211 }
212
213 #[test]
214 fn adjusts_values_using_positive_and_negative_indexes() {
215 assert_eq!(adjust(1, |value| value * 2, &[1, 2, 3]), vec![1, 4, 3]);
216 assert_eq!(adjust(-1, |value| value + 10, &[1, 2, 3]), vec![1, 2, 13]);
217 }
218
219 #[test]
220 fn drops_last_for_slices_and_strings() {
221 assert_eq!(drop_last(&[1, 2, 3][..]), vec![1, 2]);
222 assert_eq!(drop_last("hello"), "hell");
223 }
224
225 #[test]
226 fn gets_last_for_slices_and_strings() {
227 assert_eq!(last(&[1, 2, 3][..]), Some(3));
228 assert_eq!(last("abc"), Some('c'));
229 assert_eq!(last(&[] as &[i32]), None);
230 }
231
232 #[test]
233 fn repeats_reverses_and_filters_values() {
234 assert_eq!(repeat("a", 3), vec!["a", "a", "a"]);
235 assert_eq!(reverse(&[1, 2, 3][..]), vec![3, 2, 1]);
236 assert_eq!(without(&[2, 4], &[1, 2, 3, 4, 5]), vec![1, 3, 5]);
237 }
238}