split_spare/
vec.rs

1use std::mem::MaybeUninit;
2use std::ptr::NonNull;
3
4/// Determines the offset of the len field within a Vec.
5#[inline]
6fn vec_len_offset_of_val<T>(vec: &mut Vec<T>) -> usize {
7    // See https://users.rust-lang.org/t/134050 for why the implementation here is the way it is. We have to work around
8    // unsound manipulations to Vec.
9    if std::mem::size_of::<T>() == 0 {
10        // ZST
11
12        // Use ManuallyDrop to avoid dropping non-existing elements caused by `set_len`.
13        let mut vec: Vec<std::mem::MaybeUninit<T>> =
14            unsafe { std::mem::transmute(Vec::<T>::new()) };
15
16        // Should be a no-op, but just in case Vec's internals require this.
17        vec.reserve(1);
18
19        let before: [usize; 3] = unsafe { std::mem::transmute_copy(&vec) };
20
21        // SAFETY:
22        // - T is zero-sized and the Vec's drop won't be called, so we can set the len to anything
23        unsafe {
24            vec.set_len(1);
25        }
26
27        let after: [usize; 3] = unsafe { std::mem::transmute_copy(&vec) };
28
29        match std::array::from_fn(|i| after[i] ^ before[i]) {
30            [_, 0, 0] => 0,
31            [0, _, 0] => 1,
32            [0, 0, _] => 2,
33            _ => unreachable!(),
34        }
35    } else {
36        // Non-ZST
37
38        // Ensure the capacity is non-zero.
39        vec.reserve(1);
40
41        // Get the ptr/cap/len triple with the length set to 0.
42        let parts = unsafe {
43            let orig_len = vec.len();
44            vec.set_len(0);
45            let parts: [usize; 3] = std::mem::transmute_copy(&*vec);
46            vec.set_len(orig_len);
47            parts
48        };
49
50        // As per the layout guarantees, *only* the length should be 0.
51        match parts {
52            [0, a, b] if a != 0 && b != 0 => 0,
53            [a, 0, b] if a != 0 && b != 0 => 1,
54            [a, b, 0] if a != 0 && b != 0 => 2,
55            _ => unreachable!(),
56        }
57    }
58}
59
60/// Safety: changing returned .2 (&mut usize) is considered the same as calling `.set_len(_)`.
61///
62/// This method provides unique access to all vec parts at once.
63#[inline]
64unsafe fn vec_split_at_spare_mut_with_len<T>(
65    vec: &mut Vec<T>,
66) -> (&mut [T], &mut [MaybeUninit<T>], &mut usize) {
67    let ptr = vec.as_mut_ptr();
68    let len = vec.len();
69    let cap = vec.capacity();
70
71    // SAFETY:
72    // - `ptr` is guaranteed to be valid for `self.len` elements
73    // - but the allocation extends out to `self.buf.capacity()` elements, possibly
74    // uninitialized
75    let spare_ptr = unsafe { ptr.add(len) }.cast::<MaybeUninit<T>>();
76    let spare_len = cap - len;
77
78    // SAFETY:
79    // - The offset returned by vec_len_offset is guaranteed to point to the len field within a Vec<T>.
80    let len_mut = unsafe {
81        NonNull::new(vec as *mut Vec<T>)
82            .unwrap()
83            .cast::<usize>()
84            .add(vec_len_offset_of_val(vec))
85            .as_mut()
86    };
87
88    // SAFETY:
89    // - `ptr` is guaranteed to be valid for `self.len` elements
90    // - `spare_ptr` is pointing one element past the buffer, so it doesn't overlap with `initialized`
91    // - `len_mut` doesn't overlap with either
92    unsafe {
93        (
94            std::slice::from_raw_parts_mut(ptr, len),
95            std::slice::from_raw_parts_mut(spare_ptr, spare_len),
96            len_mut,
97        )
98    }
99}
100
101/// A copy of `alloc::vec::set_len_on_drop`.
102mod set_len_on_drop {
103    // Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
104    //
105    // The idea is: The length field in SetLenOnDrop is a local variable
106    // that the optimizer will see does not alias with any stores through the Vec's data
107    // pointer. This is a workaround for alias analysis issue #32155
108    pub(super) struct SetLenOnDrop<'a> {
109        len: &'a mut usize,
110        local_len: usize,
111    }
112
113    impl<'a> SetLenOnDrop<'a> {
114        #[inline]
115        pub(super) fn new(len: &'a mut usize) -> Self {
116            SetLenOnDrop {
117                local_len: *len,
118                len,
119            }
120        }
121
122        #[inline]
123        pub(super) fn increment_len(&mut self, increment: usize) {
124            self.local_len += increment;
125        }
126    }
127
128    impl Drop for SetLenOnDrop<'_> {
129        #[inline]
130        fn drop(&mut self) {
131            *self.len = self.local_len;
132        }
133    }
134}
135
136use set_len_on_drop::SetLenOnDrop;
137
138#[cold]
139fn panic_exceeded_capacity() -> ! {
140    panic!("Insufficient capacity reserved to write all elements!")
141}
142
143pub struct Spare<'a, T> {
144    len_mut: &'a mut usize,
145    slots: std::slice::IterMut<'a, MaybeUninit<T>>,
146}
147
148impl<'a, T> Spare<'a, T> {
149    pub fn push(&mut self, item: T) {
150        let Some(slot) = self.slots.next() else {
151            panic_exceeded_capacity();
152        };
153        slot.write(item);
154        *self.len_mut += 1;
155    }
156}
157
158impl<T> std::iter::Extend<T> for Spare<'_, T> {
159    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
160        let mut len = SetLenOnDrop::new(self.len_mut);
161        for item in iter.into_iter() {
162            let Some(slot) = self.slots.next() else {
163                panic_exceeded_capacity();
164            };
165            slot.write(item);
166            len.increment_len(1);
167        }
168    }
169}
170
171impl<T> crate::SplitSpare<T> for Vec<T> {
172    type Spare<'a>
173        = Spare<'a, T>
174    where
175        Self: 'a;
176
177    fn split_spare<'s>(&'s mut self) -> (&'s mut [T], Self::Spare<'s>) {
178        let (initialized, spare, len_mut) = unsafe { vec_split_at_spare_mut_with_len(self) };
179        let spare = Spare {
180            len_mut,
181            slots: spare.iter_mut(),
182        };
183        (initialized, spare)
184    }
185
186    fn reserve_split_spare<'s>(&'s mut self, additional: usize) -> (&'s mut [T], Self::Spare<'s>) {
187        self.reserve(additional);
188        self.split_spare()
189    }
190}
191
192#[cfg(test)]
193mod tests {
194    use crate::SplitSpare;
195
196    #[test]
197    fn reserve_split_spare_works() {
198        let mut vec = vec![1, 2, 3];
199
200        let (init, mut spare) = vec.reserve_split_spare(3);
201
202        assert_eq!(init, &[1, 2, 3]);
203
204        spare.extend(init.iter().copied().map(|i| i + init.len()));
205
206        assert_eq!(vec, &[1, 2, 3, 4, 5, 6]);
207    }
208
209    #[test]
210    #[should_panic(expected = "Insufficient capacity reserved to write all elements!")]
211    fn exceed() {
212        let mut vec: Vec<i32> = Vec::new();
213
214        let (init, mut spare) = vec.split_spare();
215
216        assert_eq!(init, &[]);
217
218        spare.extend([1, 2, 3].iter().copied());
219    }
220}