dyn_slice/
iter_mut.rs

1use core::{
2    iter::FusedIterator,
3    mem::transmute,
4    ptr::{metadata, DynMetadata, Pointee},
5};
6
7use crate::DynSliceMut;
8
9/// Mutable dyn slice iterator
10pub struct IterMut<'a, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>>> {
11    pub(crate) slice: DynSliceMut<'a, Dyn>,
12}
13
14impl<'a, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>> + 'a> Iterator for IterMut<'a, Dyn> {
15    type Item = &'a mut Dyn;
16
17    fn next(&mut self) -> Option<Self::Item> {
18        if self.slice.is_empty() {
19            None
20        } else {
21            // SAFETY:
22            // As the slice is not empty, it must have a first element and a valid vtable pointer, which
23            // can be transmuted to `DynMetadata<Dyn>`.
24            // The data is guaranteed to live for at least 'a, and not have a mutable reference to it
25            // in that time, so the lifetime can be extended.
26            let element: &'a mut Dyn = unsafe { transmute(self.slice.first_unchecked_mut()) };
27
28            // SAFETY:
29            // As the slice is not empty, incrementing the pointer by one unit of the underlying type will
30            // yield either a valid pointer of the next element, or will yield a pointer one byte after the
31            // last element, which is valid as per [`core::ptr::const_ptr::add`]'s safety section.
32            self.slice.0.data = unsafe { self.slice.data.byte_add(metadata(element).size_of()) };
33            self.slice.0.len -= 1;
34
35            Some(element)
36        }
37    }
38
39    #[inline]
40    fn size_hint(&self) -> (usize, Option<usize>) {
41        let remaining = self.slice.len();
42        (remaining, Some(remaining))
43    }
44
45    #[inline]
46    fn count(self) -> usize {
47        self.slice.len()
48    }
49
50    fn nth(&mut self, n: usize) -> Option<Self::Item> {
51        if n >= self.slice.len() {
52            self.slice.0.len = 0;
53            return None;
54        }
55
56        // SAFETY:
57        // The above conditional guarantees that the slice is not empty and therefore has a valid vtable
58        // pointer, which can be transmuted to a `DynMetadata<Dyn>`.
59        let metadata: DynMetadata<Dyn> = unsafe { transmute(self.slice.vtable_ptr) };
60
61        // SAFETY:
62        // As `n < slice.len()`, adding `n` units of the underlying type to the pointer will yield a valid
63        // pointer in the slice.
64        self.slice.0.data = unsafe { self.slice.data.byte_add(metadata.size_of() * n) };
65        self.slice.0.len -= n;
66
67        self.next()
68    }
69
70    fn last(mut self) -> Option<Self::Item> {
71        // SAFETY:
72        // The data is guaranteed to live for at least 'a, and not have a mutable reference to it
73        // in that time, so the lifetime can be extended.
74        unsafe { transmute(self.slice.last_mut()) }
75    }
76}
77
78impl<'a, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>> + 'a> DoubleEndedIterator
79    for IterMut<'a, Dyn>
80{
81    fn next_back(&mut self) -> Option<Self::Item> {
82        if self.slice.is_empty() {
83            None
84        } else {
85            let element: &'a mut Dyn =
86                // SAFETY:
87                // As the slice is not empty, it must have a last element (at `slice.len() - 1`) and a valid
88                // vtable pointer, which can be transmuted to `DynMetadata<Dyn>`.
89                // The data is guaranteed to live for at least 'a, and not have another mutable reference to it
90                // in that time, so the lifetime can be extended.
91                unsafe { transmute(self.slice.get_unchecked_mut(self.slice.len - 1)) };
92
93            self.slice.0.len -= 1;
94
95            Some(element)
96        }
97    }
98
99    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
100        if n >= self.slice.len() {
101            self.slice.0.len = 0;
102            return None;
103        }
104
105        self.slice.0.len -= n;
106
107        self.next_back()
108    }
109}
110
111impl<'a, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>> + 'a> ExactSizeIterator
112    for IterMut<'a, Dyn>
113{
114    #[inline]
115    fn len(&self) -> usize {
116        self.slice.len()
117    }
118}
119
120impl<'a, Dyn: ?Sized + Pointee<Metadata = DynMetadata<Dyn>> + 'a> FusedIterator
121    for IterMut<'a, Dyn>
122{
123}
124
125#[cfg(test)]
126mod test {
127    use crate::standard::partial_eq;
128
129    #[test]
130    fn test_next() {
131        let array = [2, 3, 5, 7, 11];
132        let mut array2 = array;
133        let mut slice = partial_eq::new_mut::<u8, _>(&mut array2);
134
135        let mut iter = slice.iter_mut();
136        for &expected in &array {
137            let actual = iter.next().expect("expected an element");
138            assert!(actual == &expected, "expected {expected}");
139        }
140    }
141
142    #[test]
143    fn test_size_hint() {
144        let array = [2, 3, 5, 7, 11];
145        let mut array2 = array;
146        let mut slice = partial_eq::new_mut::<u8, _>(&mut array2);
147
148        let mut iter = slice.iter_mut();
149        for expected in (1..=array.len()).rev() {
150            let (lower, Some(upper)) = iter.size_hint() else {
151                panic!("expected an upper bound");
152            };
153
154            assert_eq!(lower, upper, "expected lower and upper bounds to be equal");
155            assert_eq!(
156                lower, expected,
157                "expected size hint to be {expected}, got {lower}"
158            );
159
160            let _ = iter.next().expect("expected an element");
161        }
162
163        let (lower, Some(upper)) = iter.size_hint() else {
164            panic!("expected an upper bound");
165        };
166
167        assert_eq!(lower, upper, "expected lower and upper bounds to be equal");
168        assert_eq!(lower, 0, "expected size hint to be 0, got {lower}");
169    }
170
171    #[test]
172    fn test_count() {
173        let array = [2, 3, 5, 7, 11];
174
175        for i in 0..=array.len() {
176            let mut array2 = array;
177            let mut slice = partial_eq::new_mut::<u8, _>(&mut array2);
178
179            let iter = slice.iter_mut();
180            let actual = iter.skip(i).count();
181
182            let expected = array.len() - i;
183
184            assert_eq!(
185                actual, expected,
186                "expected count to be {expected}, got {actual}"
187            );
188        }
189    }
190
191    #[test]
192    fn test_nth() {
193        let array = [2, 3, 5, 7, 11];
194        let mut array2 = array;
195        let mut slice = partial_eq::new_mut::<u8, _>(&mut array2);
196
197        let mut iter = slice.iter_mut();
198
199        #[allow(clippy::iter_nth_zero)]
200        let actual = iter.nth(0).expect("expected an element");
201        assert!(actual == &2, "expected 2");
202
203        assert!(
204            iter.nth(1).expect("expected an element") == &5,
205            "expected 5"
206        );
207        assert_eq!(iter.size_hint().0, 2, "expected 2 elements left");
208
209        assert!(iter.nth(2).is_none(), "expected none");
210        assert_eq!(iter.size_hint().0, 0, "expected 0 elements left");
211    }
212
213    #[test]
214    fn test_last() {
215        let array = [2, 3, 5, 7, 11];
216        let mut array2 = array;
217        let mut slice = partial_eq::new_mut::<u8, _>(&mut array2);
218
219        assert!(
220            slice.iter_mut().last().expect("expected an element") == &11,
221            "expected 11"
222        );
223    }
224
225    #[test]
226    fn test_next_back() {
227        let array = [2, 3, 5, 7, 11];
228        let mut array2 = array;
229        let mut slice = partial_eq::new_mut::<u8, _>(&mut array2);
230
231        let mut iter = slice.iter_mut();
232        for &expected in array.iter().rev() {
233            let actual = iter.next_back().expect("expected an element");
234            assert!(actual == &expected, "expected {expected}");
235        }
236    }
237
238    #[test]
239    fn test_nth_back() {
240        let array = [2, 3, 5, 7, 11];
241        let mut array2 = array;
242        let mut slice = partial_eq::new_mut::<u8, _>(&mut array2);
243
244        let mut iter = slice.iter_mut();
245
246        #[allow(clippy::iter_nth_zero)]
247        let actual = iter.nth_back(0).expect("expected an element");
248        assert!(actual == &11, "expected 11");
249
250        assert!(
251            iter.nth_back(1).expect("expected an element") == &5,
252            "expected 5"
253        );
254        assert_eq!(iter.size_hint().0, 2, "expected 2 elements left");
255
256        assert!(iter.nth_back(2).is_none(), "expected none");
257        assert_eq!(iter.size_hint().0, 0, "expected 0 elements left");
258    }
259
260    #[test]
261    fn test_bidirectional() {
262        let mut array = [2, 3, 5, 7, 11];
263        let mut slice = partial_eq::new_mut::<u8, _>(&mut array);
264
265        let mut iter = slice.iter_mut();
266
267        assert!(
268            iter.next().expect("expected an element") == &2,
269            "expected 2"
270        );
271        assert_eq!(iter.size_hint().0, 4, "expected 4 elements left");
272
273        assert!(
274            iter.next_back().expect("expected an element") == &11,
275            "expected 11"
276        );
277        assert_eq!(iter.size_hint().0, 3, "expected 3 elements left");
278
279        assert!(
280            iter.nth(1).expect("expected an element") == &5,
281            "expected 5"
282        );
283        assert_eq!(iter.size_hint().0, 1, "expected 1 element left");
284
285        assert!(
286            iter.nth_back(0).expect("expected an element") == &7,
287            "expected 7"
288        );
289        assert_eq!(iter.size_hint().0, 0, "expected 0 elements left");
290    }
291}