lowdash/
splice.rs

1/// Inserts elements into a collection at a specified index, handling negative indices and overflow.
2/// Returns a new `Vec<T>` with the elements inserted.
3///
4/// **Time Complexity:** O(n), where n is the number of elements in the collection.
5///
6/// # Arguments
7///
8/// * `collection` - A slice of items in which to perform the insertion.
9/// * `i` - The index at which to insert the elements. Can be negative to indicate an offset from the end.
10/// * `elements` - A slice of elements to insert.
11///
12/// # Type Parameters
13///
14/// * `T` - The type of elements in the collection. Must implement `Clone`.
15///
16/// # Returns
17///
18/// * `Vec<T>` - A new vector with the specified elements inserted.
19///
20/// # Examples
21///
22/// ```rust
23/// use lowdash::splice;
24///
25/// let numbers = vec![1, 2, 3, 4, 5];
26/// let elements = vec![99, 100];
27/// let result = splice(&numbers, 2, &elements);
28/// assert_eq!(result, vec![1, 2, 99, 100, 3, 4, 5]);
29/// ```
30///
31/// ```rust
32/// use lowdash::splice;
33///
34/// let numbers = vec![1, 2, 3, 4, 5];
35/// let elements = vec![99, 100];
36/// // Insert at the end
37/// let result = splice(&numbers, 10, &elements);
38/// assert_eq!(result, vec![1, 2, 3, 4, 5, 99, 100]);
39/// ```
40///
41/// ```rust
42/// use lowdash::splice;
43///
44/// let numbers = vec![1, 2, 3, 4, 5];
45/// let elements = vec![99];
46/// // Insert at negative index (-2 means len - 2 = 3)
47/// let result = splice(&numbers, -2, &elements);
48/// assert_eq!(result, vec![1, 2, 3, 99, 4, 5]);
49/// ```
50///
51/// ```rust
52/// use lowdash::splice;
53///
54/// let numbers = vec![1, 2, 3, 4, 5];
55/// let elements = vec![99];
56/// // Negative index beyond the start, insert at beginning
57/// let result = splice(&numbers, -10, &elements);
58/// assert_eq!(result, vec![99, 1, 2, 3, 4, 5]);
59/// ```
60pub fn splice<T>(collection: &[T], i: isize, elements: &[T]) -> Vec<T>
61where
62    T: Clone,
63{
64    let size_collection = collection.len() as isize;
65    let size_elements = elements.len();
66
67    let mut output = Vec::with_capacity(collection.len() + size_elements);
68
69    if size_elements == 0 {
70        output.extend_from_slice(collection);
71        return output;
72    }
73
74    let mut index = i;
75
76    if index > size_collection {
77        index = size_collection;
78    } else if index < -size_collection {
79        index = -size_collection;
80    }
81
82    if index < 0 {
83        index += size_collection;
84        if index < 0 {
85            index = 0;
86        }
87    }
88
89    let usize_index = index as usize;
90
91    output.extend_from_slice(&collection[..usize_index]);
92    output.extend_from_slice(elements);
93    output.extend_from_slice(&collection[usize_index..]);
94
95    output
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    #[derive(Debug, PartialEq, Clone)]
103    struct Person {
104        name: String,
105        age: u32,
106    }
107
108    #[test]
109    fn test_splice_basic_insert() {
110        let numbers = vec![1, 2, 3, 4, 5];
111        let elements = vec![99, 100];
112        let result = splice(&numbers, 2, &elements);
113        assert_eq!(result, vec![1, 2, 99, 100, 3, 4, 5]);
114    }
115
116    #[test]
117    fn test_splice_insert_at_end() {
118        let numbers = vec![1, 2, 3, 4, 5];
119        let elements = vec![99, 100];
120        let result = splice(&numbers, 10, &elements);
121        assert_eq!(result, vec![1, 2, 3, 4, 5, 99, 100]);
122    }
123
124    #[test]
125    fn test_splice_insert_negative_index() {
126        let numbers = vec![1, 2, 3, 4, 5];
127        let elements = vec![99];
128        let result = splice(&numbers, -2, &elements);
129        assert_eq!(result, vec![1, 2, 3, 99, 4, 5]);
130    }
131
132    #[test]
133    fn test_splice_negative_index_beyond_start() {
134        let numbers = vec![1, 2, 3, 4, 5];
135        let elements = vec![99];
136        let result = splice(&numbers, -10, &elements);
137        assert_eq!(result, vec![99, 1, 2, 3, 4, 5]);
138    }
139
140    #[test]
141    fn test_splice_no_elements() {
142        let numbers = vec![1, 2, 3, 4, 5];
143        let elements: Vec<i32> = vec![];
144        let result = splice(&numbers, 2, &elements);
145        assert_eq!(result, vec![1, 2, 3, 4, 5]);
146    }
147
148    #[test]
149    fn test_splice_insert_at_start() {
150        let numbers = vec![2, 3, 4];
151        let elements = vec![0, 1];
152        let result = splice(&numbers, 0, &elements);
153        assert_eq!(result, vec![0, 1, 2, 3, 4]);
154    }
155
156    #[test]
157    fn test_splice_insert_all_elements() {
158        let numbers = vec![1, 2, 3];
159        let elements = vec![4, 5, 6];
160        let result = splice(&numbers, 1, &elements);
161        assert_eq!(result, vec![1, 4, 5, 6, 2, 3]);
162    }
163
164    #[test]
165    fn test_splice_insert_at_exemplary_middle() {
166        let numbers = vec![1, 2, 3, 4, 5];
167        let elements = vec![99];
168        let result = splice(&numbers, 3, &elements);
169        assert_eq!(result, vec![1, 2, 3, 99, 4, 5]);
170    }
171
172    #[test]
173    fn test_splice_with_structs() {
174        let alice = Person {
175            name: "Alice".to_string(),
176            age: 25,
177        };
178        let bob = Person {
179            name: "Bob".to_string(),
180            age: 30,
181        };
182        let carol = Person {
183            name: "Carol".to_string(),
184            age: 35,
185        };
186        let dave = Person {
187            name: "Dave".to_string(),
188            age: 40,
189        };
190
191        let people = vec![alice.clone(), bob.clone(), carol.clone()];
192        let elements = vec![dave.clone()];
193        let result = splice(&people, 1, &elements);
194        assert_eq!(
195            result,
196            vec![alice.clone(), dave.clone(), bob.clone(), carol.clone()]
197        );
198    }
199
200    #[test]
201    fn test_splice_with_strings() {
202        let fruits = vec!["apple", "banana", "cherry"];
203        let elements = vec!["date", "elderberry"];
204        let result = splice(&fruits, 2, &elements);
205        assert_eq!(
206            result,
207            vec!["apple", "banana", "date", "elderberry", "cherry"]
208        );
209    }
210
211    #[test]
212    fn test_splice_with_floats() {
213        let numbers = vec![1.1, 2.2, 3.3];
214        let elements = vec![4.4, 5.5];
215        let result = splice(&numbers, -1, &elements);
216        assert_eq!(result, vec![1.1, 2.2, 4.4, 5.5, 3.3]);
217    }
218
219    #[test]
220    fn test_splice_insert_zero_elements() {
221        let numbers = vec![1, 2, 3];
222        let elements: Vec<i32> = vec![];
223        let result = splice(&numbers, 1, &elements);
224        assert_eq!(result, vec![1, 2, 3]);
225    }
226
227    #[test]
228    fn test_splice_insert_at_negative_index_consider_length() {
229        let numbers = vec![1, 2, 3, 4];
230        let elements = vec![99];
231        let result = splice(&numbers, -3, &elements); // len=4, -3 => 1
232        assert_eq!(result, vec![1, 99, 2, 3, 4]);
233    }
234}