Skip to content

Commit 4f60dc0

Browse files
Add alteration methods to IArray
Includes IArray::make_mut, which works similar to Rc::make_mut, as well as insertion and removal methods, all of which copy-on-write the array.
1 parent 238d464 commit 4f60dc0

File tree

1 file changed

+168
-0
lines changed

1 file changed

+168
-0
lines changed

Diff for: src/array.rs

+168
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ impl<T: ImplicitClone + 'static> FromIterator<T> for IArray<T> {
4242
}
4343
}
4444

45+
impl<T: ImplicitClone + 'static> Extend<T> for IArray<T> {
46+
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
47+
self.insert_many(self.len(), iter);
48+
}
49+
}
50+
4551
impl<T: ImplicitClone + 'static> ImplicitClone for IArray<T> {}
4652

4753
impl<T: ImplicitClone + 'static> From<&'static [T]> for IArray<T> {
@@ -160,6 +166,161 @@ impl<T: ImplicitClone + 'static> IArray<T> {
160166
Self::Rc(a) => a.get(index).cloned(),
161167
}
162168
}
169+
170+
/// Makes a mutable reference into the array.
171+
///
172+
/// If this array is an `Rc` with no other strong or weak references, returns
173+
/// a mutable slice of the contained data without any cloning. Otherwise, it clones the
174+
/// data into a new array and returns a mutable slice into that.
175+
///
176+
/// # Example
177+
///
178+
/// ```
179+
/// # use implicit_clone::unsync::*;
180+
/// # use std::rc::Rc;
181+
/// // This will reuse the Rc storage
182+
/// let mut v1 = IArray::<u8>::Rc(Rc::new([1,2,3]));
183+
/// v1.make_mut()[1] = 123;
184+
/// assert_eq!(&[1,123,3], v1.as_slice());
185+
///
186+
/// // This will create a new copy
187+
/// let mut v2 = IArray::<u8>::Static(&[1,2,3]);
188+
/// v2.make_mut()[1] = 123;
189+
/// assert_eq!(&[1,123,3], v2.as_slice());
190+
/// ```
191+
#[inline]
192+
pub fn make_mut(&mut self) -> &mut [T] {
193+
// This code is somewhat weirdly written to work around https://github.com/rust-lang/rust/issues/54663 -
194+
// we can't just check if this is an Rc with one reference with get_mut in an if branch and copy otherwise,
195+
// since returning the mutable slice extends its lifetime for the rest of the function.
196+
match self {
197+
Self::Rc(ref mut rc) => {
198+
if Rc::get_mut(rc).is_none() {
199+
*rc = rc.iter().cloned().collect::<Rc<[T]>>();
200+
}
201+
Rc::get_mut(rc).unwrap()
202+
}
203+
Self::Static(slice) => {
204+
*self = Self::Rc(slice.iter().cloned().collect());
205+
match self {
206+
Self::Rc(rc) => Rc::get_mut(rc).unwrap(),
207+
_ => unreachable!(),
208+
}
209+
}
210+
}
211+
}
212+
213+
/// Inserts several objects into the array.
214+
///
215+
/// This overwrites `self` to a new refcounted array with clones of the previous items,
216+
/// with items from the `values` iterator inserted starting at the specified index, shifting
217+
/// later items down.
218+
///
219+
/// # Panics
220+
///
221+
/// Panics if the index is greater than one more than the length of the array.
222+
///
223+
/// # Example
224+
///
225+
/// ```
226+
/// # use implicit_clone::unsync::*;
227+
/// let mut v = IArray::<u8>::Static(&[1,2,6]);
228+
/// v.insert_many(2, [3,4,5]);
229+
/// assert_eq!(&[1,2,3,4,5,6], v.as_slice());
230+
/// ```
231+
pub fn insert_many<I: IntoIterator<Item = T>>(&mut self, index: usize, values: I) {
232+
let head = self.as_slice()[..index].iter().cloned();
233+
let tail = self.as_slice()[index..].iter().cloned();
234+
let rc = head.chain(values).chain(tail).collect();
235+
*self = Self::Rc(rc);
236+
}
237+
238+
/// Inserts an object into the array.
239+
///
240+
/// This overwrites `self` to a new refcounted array with clones of the previous items,
241+
/// with `value` inserted at the `index`, shifting later items down.
242+
///
243+
/// [`Self::insert_many`] will be more efficient if inserting multiple items.
244+
///
245+
/// # Panics
246+
///
247+
/// Panics if the index is greater than one more than the length of the array.
248+
///
249+
/// # Example
250+
///
251+
/// ```
252+
/// # use implicit_clone::unsync::*;
253+
/// let mut v = IArray::<u8>::Static(&[1,2,4]);
254+
/// v.insert(2, 3);
255+
/// assert_eq!(&[1,2,3,4], v.as_slice());
256+
/// ```
257+
pub fn insert(&mut self, index: usize, value: T) {
258+
self.insert_many(index, std::iter::once(value));
259+
}
260+
261+
/// Adds an object to the end of the array.
262+
///
263+
/// This overwrites `self` to a new refcounted array with clones of the previous items,
264+
/// with `value` added at the end.
265+
///
266+
/// [`Self::extend`] will be more efficient if inserting multiple items.
267+
///
268+
/// # Example
269+
///
270+
/// ```
271+
/// # use implicit_clone::unsync::*;
272+
/// let mut v = IArray::<u8>::Static(&[1,2,3]);
273+
/// v.push(4);
274+
/// assert_eq!(&[1,2,3,4], v.as_slice());
275+
/// ```
276+
pub fn push(&mut self, value: T) {
277+
self.insert(self.len(), value);
278+
}
279+
280+
/// Removes a range of items from the array.
281+
///
282+
/// This overwrites `self` to a new refcounted array with clones of the previous items, excluding
283+
/// the items covered by `range`, with later items shifted up.
284+
///
285+
/// # Panics
286+
///
287+
/// Panics if the range is out of bounds.
288+
///
289+
/// # Example
290+
///
291+
/// ```
292+
/// # use implicit_clone::unsync::*;
293+
/// let mut v = IArray::<u8>::Static(&[1,2,10,20,3]);
294+
/// v.remove_range(2..4);
295+
/// assert_eq!(&[1,2,3], v.as_slice());
296+
/// ```
297+
pub fn remove_range(&mut self, range: std::ops::Range<usize>) {
298+
let head = self.as_slice()[..range.start].iter().cloned();
299+
let tail = self.as_slice()[range.end..].iter().cloned();
300+
let rc = head.chain(tail).collect();
301+
*self = Self::Rc(rc);
302+
}
303+
304+
/// Removes an item from the array.
305+
///
306+
/// This overwrites `self` to a new refcounted array with clones of the previous items, excluding
307+
/// the items at `index`, with later items shifted up.
308+
///
309+
/// # Panics
310+
///
311+
/// Panics if the index is out of bounds.
312+
///
313+
/// # Example
314+
///
315+
/// ```
316+
/// # use implicit_clone::unsync::*;
317+
/// let mut v = IArray::<u8>::Static(&[1,2,10,3]);
318+
/// v.remove(2);
319+
/// assert_eq!(&[1,2,3], v.as_slice());
320+
/// ```
321+
pub fn remove(&mut self, index: usize) {
322+
self.remove_range(index..index + 1)
323+
}
163324
}
164325

165326
impl<'a, T, U, const N: usize> PartialEq<&'a [U; N]> for IArray<T>
@@ -276,4 +437,11 @@ mod test_array {
276437
const _ARRAY_F32: IArray<f32> = IArray::Static(&[]);
277438
const _ARRAY_F64: IArray<f64> = IArray::Static(&[]);
278439
}
440+
441+
#[test]
442+
fn extend() {
443+
let mut array = [1, 2, 3].into_iter().collect::<IArray<u32>>();
444+
array.extend([4, 5, 6]);
445+
assert_eq!(&[1, 2, 3, 4, 5, 6], array.as_slice());
446+
}
279447
}

0 commit comments

Comments
 (0)