dyn_slice/
dyn_slice_mut.rs

1use core::{
2    mem::transmute,
3    ops::{Bound, Deref, Index, IndexMut, RangeBounds},
4    ptr::{self, DynMetadata, Pointee},
5    slice,
6};
7
8use crate::{DynSlice, Iter, IterMut};
9
10/// `&mut dyn [Trait]`
11///
12/// A mutable type erased slice of elements that implement a trait.
13///
14/// # Example
15/// ```
16/// use dyn_slice::standard::add_assign;
17///
18/// let mut array = [1, 2, 3, 4, 5];
19/// let mut slice = add_assign::new_mut(&mut array);
20/// slice.iter_mut().for_each(|x| *x += 10);
21/// assert_eq!(array, [11, 12, 13, 14, 15]);
22/// ```
23#[repr(transparent)]
24pub struct DynSliceMut<'a, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>>>(
25    pub(crate) DynSlice<'a, Dyn>,
26);
27
28impl<'a, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>>> AsRef<DynSlice<'a, Dyn>>
29    for DynSliceMut<'a, Dyn>
30{
31    #[inline]
32    fn as_ref(&self) -> &DynSlice<'a, Dyn> {
33        &self.0
34    }
35}
36
37impl<'a, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>>> Deref for DynSliceMut<'a, Dyn> {
38    type Target = DynSlice<'a, Dyn>;
39
40    #[inline]
41    fn deref(&self) -> &Self::Target {
42        &self.0
43    }
44}
45
46impl<'a, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>>> DynSliceMut<'a, Dyn> {
47    #[inline]
48    #[must_use]
49    /// Construct a mutable dyn slice given a mutable slice and a vtable pointer.
50    ///
51    /// # Safety
52    /// Caller must ensure that `vtable_ptr` is a valid instance of `DynMetadata` for `DynSliceFromType` and `Dyn` transmuted, or optionally, a null pointer if `value.len() == 0`.
53    pub unsafe fn with_vtable_ptr<DynSliceFromType>(
54        value: &'a mut [DynSliceFromType],
55        vtable_ptr: *const (),
56    ) -> Self {
57        Self::from_parts(vtable_ptr, value.len(), value.as_mut_ptr().cast())
58    }
59
60    #[inline]
61    #[must_use]
62    /// Construct a mutable dyn slice given a mutable slice and a `DynMetadata` instance.
63    ///
64    /// # Safety
65    /// Caller must ensure that `metadata` is a valid instance of `DynMetadata` for `DynSliceFromType` and `Dyn`.
66    pub unsafe fn with_metadata<DynSliceFromType>(
67        value: &'a mut [DynSliceFromType],
68        metadata: DynMetadata<Dyn>,
69    ) -> Self {
70        Self::with_vtable_ptr(value, transmute(metadata))
71    }
72
73    #[inline]
74    #[must_use]
75    /// Construct a mutable dyn slice from raw parts.
76    ///
77    /// # Safety
78    /// Caller must ensure that:
79    /// - `vtable_ptr` is a valid instance of `DynMetadata` transmuted, or optionally, a null pointer if `len == 0`,
80    /// - `len` <= the length of the slice in memory from the `data` pointer,
81    /// - `data` is a valid pointer to the slice,
82    /// - the underlying slice is the same layout as [`[T]`](https://doc.rust-lang.org/reference/type-layout.html#slice-layout)
83    pub const unsafe fn from_parts(vtable_ptr: *const (), len: usize, data: *mut ()) -> Self {
84        Self(DynSlice::from_parts(vtable_ptr, len, data))
85    }
86
87    #[inline]
88    #[must_use]
89    /// Construct a mutable dyn slice from raw parts with a `DynMetadata` instance rather than a vtable pointer.
90    ///
91    /// # Safety
92    /// Caller must ensure that:
93    /// - `metadata` is a valid instance of `DynMetadata`,
94    /// - `len` <= the length of the slice in memory from the `data` pointer,
95    /// - `data` is a valid pointer to the slice,
96    /// - the underlying slice is the same layout as [`[T]`](https://doc.rust-lang.org/reference/type-layout.html#slice-layout)
97    pub const unsafe fn from_parts_with_metadata(
98        metadata: DynMetadata<Dyn>,
99        len: usize,
100        data: *mut (),
101    ) -> Self {
102        Self::from_parts(transmute(metadata), len, data)
103    }
104
105    #[inline]
106    #[must_use]
107    /// Returns a mutable pointer to the underlying slice, which may be null if the slice is empty.
108    pub fn as_mut_ptr(&mut self) -> *mut () {
109        self.0.data.cast_mut()
110    }
111
112    #[inline]
113    #[must_use]
114    /// Returns a mutable reference to the first element, without doing bounds checking.
115    ///
116    /// # Safety
117    /// The caller must ensure that `!self.is_empty()`
118    /// Calling this on an empty `DynSlice` will result in a segfault!
119    pub unsafe fn first_unchecked_mut(&mut self) -> &mut Dyn {
120        debug_assert!(!self.is_empty(), "[dyn-slice] slice is empty!");
121        debug_assert!(
122            !self.vtable_ptr.is_null(),
123            "[dyn-slice] vtable pointer is null on access!"
124        );
125
126        &mut *ptr::from_raw_parts_mut::<Dyn>(self.as_mut_ptr(), transmute(self.vtable_ptr()))
127    }
128
129    #[must_use]
130    /// Returns a mutable reference to the first element of the slice, or `None` if it is empty.
131    ///
132    /// # Example
133    /// ```
134    /// use dyn_slice::standard::add_assign;
135    ///
136    /// let mut array = [1, 2, 3, 4, 5];
137    /// let mut slice = add_assign::new_mut(&mut array);
138    ///
139    /// *slice.first_mut().unwrap() += 10;
140    /// assert_eq!(array, [11, 2, 3, 4, 5]);
141    /// ```
142    pub fn first_mut(&mut self) -> Option<&mut Dyn> {
143        (!self.0.is_empty()).then(|| {
144            debug_assert!(
145                !self.vtable_ptr.is_null(),
146                "[dyn-slice] vtable pointer is null on access!"
147            );
148
149            // SAFETY:
150            // The above statement ensures that slice is not empty, and
151            // therefore has a first (index 0) element and a valid vtable pointer.
152            unsafe { self.first_unchecked_mut() }
153        })
154    }
155
156    #[must_use]
157    /// Returns a mutable reference to the last element of the slice, or `None` if it is empty.
158    ///
159    /// # Example
160    /// ```
161    /// use dyn_slice::standard::add_assign;
162    ///
163    /// let mut array = [1, 2, 3, 4, 5];
164    /// let mut slice = add_assign::new_mut(&mut array);
165    ///
166    /// *slice.last_mut().unwrap() += 10;
167    /// assert_eq!(array, [1, 2, 3, 4, 15]);
168    /// ```
169    pub fn last_mut(&mut self) -> Option<&mut Dyn> {
170        (!self.0.is_empty()).then(|| {
171            // SAFETY:
172            // The above statement ensures that slice is not empty, and
173            // therefore has a last (index len - 1) element and a valid vtable pointer.
174            unsafe { self.get_unchecked_mut(self.0.len - 1) }
175        })
176    }
177
178    #[must_use]
179    /// Returns a mutable reference to the element at the given `index` or `None` if the `index` is out of bounds.
180    ///
181    /// # Example
182    /// ```
183    /// use dyn_slice::standard::add_assign;
184    ///
185    /// let mut array = [1, 2, 3, 4, 5];
186    /// let mut slice = add_assign::new_mut(&mut array);
187    ///
188    /// *slice.get_mut(2).unwrap() += 10;
189    /// assert_eq!(array, [1, 2, 13, 4, 5]);
190    /// ```
191    pub fn get_mut(&mut self, index: usize) -> Option<&mut Dyn> {
192        (index < self.0.len).then(|| {
193            // SAFETY:
194            // The above inequality ensures that the index is less than the
195            // length, and is therefore valid. This also ensures that the slice
196            // has a valid vtable pointer because the slice guaranteed to not be empty.
197            unsafe { self.get_unchecked_mut(index) }
198        })
199    }
200
201    #[inline]
202    #[must_use]
203    /// Returns a mutable reference to the element at the given `index`, without doing bounds checking.
204    ///
205    /// # Safety
206    /// The caller must ensure that `index < self.len()`
207    /// Calling this on an empty dyn Slice will result in a segfault!
208    pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut Dyn {
209        debug_assert!(
210            index < self.len,
211            "[dyn-slice] index is greater than length!"
212        );
213        debug_assert!(
214            !self.vtable_ptr.is_null(),
215            "[dyn-slice] vtable pointer is null on access!"
216        );
217
218        let metadata = transmute::<_, DynMetadata<Dyn>>(self.0.vtable_ptr());
219        &mut *ptr::from_raw_parts_mut::<Dyn>(
220            self.as_mut_ptr().byte_add(metadata.size_of() * index),
221            metadata,
222        )
223    }
224
225    #[inline]
226    #[must_use]
227    /// Get a mutable sub-slice from the `start` index with the `len`, without doing bounds checking.
228    ///
229    /// # Safety
230    /// Caller must ensure that:
231    /// - `start < self.len()`
232    /// - `len <= self.len() - start`
233    pub unsafe fn slice_unchecked_mut(&mut self, start: usize, len: usize) -> DynSliceMut<Dyn> {
234        // NOTE: DO NOT MAKE THIS FUNCTION RETURN `Self` as `Self` comes with an incorrect lifetime
235        debug_assert!(
236            start + len <= self.len,
237            "[dyn-slice] sub-slice is out of bounds!"
238        );
239
240        let metadata = transmute::<_, DynMetadata<Dyn>>(self.0.vtable_ptr());
241        Self::from_parts_with_metadata(
242            metadata,
243            len,
244            self.as_mut_ptr().byte_add(metadata.size_of() * start),
245        )
246    }
247
248    #[must_use]
249    /// Returns a mutable sub-slice from the `start` index with the `len` or `None` if the slice is out of bounds.
250    ///
251    /// # Example
252    /// ```
253    /// use dyn_slice::standard::add_assign;
254    ///
255    /// let mut array = [1, 2, 3, 4, 5];
256    /// let mut slice = add_assign::new_mut(&mut array);
257    ///
258    /// slice.slice_mut(1..4).unwrap().iter_mut().for_each(|x| *x += 10);
259    /// slice.slice_mut(2..).unwrap().iter_mut().for_each(|x| *x += 10);
260    /// slice.slice_mut(5..).unwrap().iter_mut().for_each(|x| *x += 10);
261    /// assert!(slice.slice(6..).is_none());
262    /// assert_eq!(array, [1, 12, 23, 24, 15]);
263    /// ```
264    pub fn slice_mut<R: RangeBounds<usize>>(&mut self, range: R) -> Option<DynSliceMut<Dyn>> {
265        // NOTE: DO NOT MAKE THIS FUNCTION RETURN `Self` as `Self` comes with an incorrect lifetime
266
267        let start_inclusive = match range.start_bound() {
268            Bound::Included(i) => *i,
269            Bound::Excluded(i) => i.checked_add(1)?,
270            Bound::Unbounded => 0,
271        };
272
273        let end_exclusive = match range.end_bound() {
274            Bound::Included(i) => i.checked_add(1)?,
275            Bound::Excluded(i) => *i,
276            Bound::Unbounded => self.0.len,
277        };
278
279        if end_exclusive > self.0.len {
280            return None;
281        }
282
283        let len = end_exclusive.checked_sub(start_inclusive)?;
284
285        // SAFETY:
286        // The above `if` statement ensures that the the end of the new slice
287        // does not exceed that of the original slice, therefore, the new
288        // slice is valid.
289        Some(unsafe { self.slice_unchecked_mut(start_inclusive, len) })
290    }
291
292    #[inline]
293    #[must_use]
294    /// Returns the underlying slice as `&mut [T]`.
295    ///
296    /// # Safety
297    /// The caller must ensure that the underlying slice is of type `[T]`.
298    pub unsafe fn downcast_unchecked_mut<T>(&mut self) -> &mut [T] {
299        slice::from_raw_parts_mut(self.as_ptr().cast_mut().cast(), self.len)
300    }
301
302    #[inline]
303    #[must_use]
304    /// Returns a mutable iterator over the slice.
305    ///
306    /// # Example
307    /// ```
308    /// use dyn_slice::standard::add_assign;
309    ///
310    /// let mut array = [1, 2, 3, 4, 5];
311    /// let mut slice = add_assign::new_mut(&mut array);
312    ///
313    /// slice.iter_mut().for_each(|x| *x += 10);
314    /// assert_eq!(array, [11, 12, 13, 14, 15]);
315    /// ```
316    pub fn iter_mut(&mut self) -> IterMut<'_, Dyn> {
317        IterMut {
318            // SAFETY:
319            // The created slice is from index 0 and has the same length as the
320            // original slice, so must be valid.
321            slice: unsafe { self.slice_unchecked_mut(0, self.len) },
322        }
323    }
324}
325
326impl<'a, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>>> Index<usize> for DynSliceMut<'a, Dyn> {
327    type Output = Dyn;
328
329    #[inline]
330    fn index(&self, index: usize) -> &Self::Output {
331        self.0.index(index)
332    }
333}
334
335impl<'a, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>>> IndexMut<usize>
336    for DynSliceMut<'a, Dyn>
337{
338    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
339        assert!(index < self.0.len, "index out of bounds");
340        debug_assert!(
341            !self.vtable_ptr.is_null(),
342            "[dyn-slice] vtable pointer is null on access!"
343        );
344
345        // SAFETY:
346        // The above assertion ensures that the index is less than the
347        // length, and is therefore valid. This also ensures that the slice
348        // has a valid vtable pointer because the slice guaranteed to not be empty.
349        unsafe { self.get_unchecked_mut(index) }
350    }
351}
352
353impl<'a, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>>> IntoIterator for DynSliceMut<'a, Dyn> {
354    type IntoIter = IterMut<'a, Dyn>;
355    type Item = &'a mut Dyn;
356
357    fn into_iter(self) -> Self::IntoIter {
358        IterMut { slice: self }
359    }
360}
361
362impl<'a, 'b, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>>> IntoIterator
363    for &'b mut DynSliceMut<'a, Dyn>
364{
365    type IntoIter = IterMut<'b, Dyn>;
366    type Item = &'b mut Dyn;
367
368    fn into_iter(self) -> Self::IntoIter {
369        self.iter_mut()
370    }
371}
372
373impl<'a, 'b, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>>> IntoIterator
374    for &'b DynSliceMut<'a, Dyn>
375{
376    type IntoIter = Iter<'b, Dyn>;
377    type Item = &'b Dyn;
378
379    fn into_iter(self) -> Self::IntoIter {
380        self.iter()
381    }
382}
383
384#[cfg(test)]
385mod test {
386    use core::{fmt::Display, ptr::addr_of};
387
388    use crate::{declare_new_fns, standard::partial_eq, DynSliceMut};
389
390    declare_new_fns!(
391        #[crate = crate]
392        display_dyn_slice Display
393    );
394    pub use display_dyn_slice::new_mut as new_display_dyn_slice;
395
396    #[test]
397    fn create_dyn_slice() {
398        let array: [u8; 5] = [1, 2, 3, 4, 5];
399        let mut array2 = array;
400
401        let dyn_slice = new_display_dyn_slice(&mut array2);
402
403        assert_eq!(dyn_slice.len(), array.len());
404        assert!(!dyn_slice.is_empty());
405
406        for (i, x) in array.iter().enumerate() {
407            assert_eq!(
408                format!(
409                    "{}",
410                    dyn_slice
411                        .get(i)
412                        .expect("failed to get an element of dyn_slice")
413                ),
414                format!("{x}"),
415            );
416        }
417    }
418
419    #[test]
420    fn empty() {
421        let mut array: [u8; 0] = [];
422
423        let dyn_slice = new_display_dyn_slice(&mut array);
424
425        assert_eq!(dyn_slice.len(), 0);
426        assert!(dyn_slice.is_empty());
427    }
428
429    #[test]
430    fn test_slice() {
431        type GetSliceFn = for<'a> fn(
432            &'a mut DynSliceMut<dyn PartialEq<i32>>,
433        ) -> DynSliceMut<'a, dyn PartialEq<i32>>;
434        type GetOptSliceFn = for<'a> fn(
435            &'a mut DynSliceMut<dyn PartialEq<i32>>,
436        ) -> Option<DynSliceMut<'a, dyn PartialEq<i32>>>;
437
438        let mut array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
439        let len = array.len();
440        let mut slice = partial_eq::new_mut(&mut array);
441        let metadata = slice.metadata().unwrap();
442        assert_eq!(slice.len(), len);
443
444        // Slices equal to the original slice
445        let full_slices: [GetSliceFn; 6] = [
446            |slice| slice.slice_mut(..).unwrap(),
447            |slice| slice.slice_mut(0..).unwrap(),
448            |slice| slice.slice_mut(..(slice.len())).unwrap(),
449            #[allow(clippy::range_minus_one)]
450            |slice| slice.slice_mut(..=(slice.len() - 1)).unwrap(),
451            |slice| slice.slice_mut(0..slice.len()).unwrap(),
452            #[allow(clippy::range_minus_one)]
453            |slice| slice.slice_mut(0..=(slice.len() - 1)).unwrap(),
454        ];
455
456        for get_sub_slice in full_slices {
457            let sub_slice = get_sub_slice(&mut slice);
458
459            assert_eq!(sub_slice.metadata(), Some(metadata));
460            assert_eq!(sub_slice.len(), len);
461            assert_eq!(sub_slice.as_ptr(), slice.as_ptr());
462        }
463
464        // Sub-slices bounded on one side
465        let sub_slice = slice.slice_mut(2..).unwrap();
466        assert_eq!(sub_slice.metadata(), Some(metadata));
467        assert_eq!(sub_slice.len(), len - 2);
468        assert_eq!(sub_slice.as_ptr(), addr_of!(slice[2]).cast());
469
470        let sub_slice = slice.slice_mut(..7).unwrap();
471        assert_eq!(sub_slice.metadata(), Some(metadata));
472        assert_eq!(sub_slice.len(), 7);
473        assert_eq!(sub_slice.as_ptr(), slice.as_ptr());
474
475        // Sub-slices bounded on both sides
476        let sub_slices: [GetSliceFn; 2] = [
477            |slice| slice.slice_mut(2..slice.len()).unwrap(),
478            #[allow(clippy::range_minus_one)]
479            |slice| slice.slice_mut(2..=(slice.len() - 1)).unwrap(),
480        ];
481
482        for get_sub_slice in sub_slices {
483            let sub_slice = get_sub_slice(&mut slice);
484
485            assert_eq!(sub_slice.metadata(), Some(metadata));
486            assert_eq!(sub_slice.len(), len - 2);
487            assert_eq!(sub_slice.as_ptr(), addr_of!(slice[2]).cast());
488        }
489
490        // Sub-slices with zero length
491        let zero_length_slices: [GetSliceFn; 4] = [
492            |slice| slice.slice_mut(0..0).unwrap(),
493            |slice| slice.slice_mut(2..2).unwrap(),
494            #[allow(clippy::reversed_empty_ranges)]
495            |slice| slice.slice_mut(2..=1).unwrap(),
496            |slice| slice.slice_mut((slice.len())..).unwrap(),
497        ];
498
499        for get_sub_slice in zero_length_slices {
500            let sub_slice = get_sub_slice(&mut slice);
501
502            assert_eq!(sub_slice.metadata(), Some(metadata));
503            assert_eq!(sub_slice.len(), 0);
504        }
505
506        // Invalid sub-slices
507        let invalid_slices: [GetOptSliceFn; 2] = [
508            #[allow(clippy::range_plus_one)]
509            |slice| slice.slice_mut(..(slice.len() + 1)),
510            |slice| slice.slice_mut(..=(slice.len())),
511        ];
512
513        for get_sub_slice in invalid_slices {
514            let sub_slice = get_sub_slice(&mut slice);
515
516            assert!(sub_slice.is_none());
517        }
518    }
519
520    #[test]
521    #[should_panic(expected = "index out of bounds")]
522    fn index_empty() {
523        let slice = partial_eq::new_mut::<u8, u8>(&mut []);
524        _ = &slice[0];
525    }
526
527    #[test]
528    fn index() {
529        let mut array = [1, 2, 3, 4];
530        let slice = partial_eq::new_mut::<u8, u8>(&mut array);
531        assert!(slice[0] == 1);
532        assert!(slice[1] == 2);
533        assert!(slice[2] == 3);
534        assert!(slice[3] == 4);
535    }
536
537    #[test]
538    #[should_panic(expected = "index out of bounds")]
539    fn index_on_bound() {
540        let mut array = [1, 2, 3, 4];
541        let slice = partial_eq::new_mut::<u8, u8>(&mut array);
542        _ = &slice[4];
543    }
544
545    #[test]
546    #[should_panic(expected = "index out of bounds")]
547    fn index_out_of_bounds() {
548        let mut array = [1, 2, 3, 4];
549        let slice = partial_eq::new_mut::<u8, u8>(&mut array);
550        _ = &slice[6];
551    }
552}