rune_alloc/
slice.rs

1pub use self::iter::{RawIter, RawIterMut};
2pub(crate) mod iter;
3
4use crate::alloc::{Allocator, Global};
5use crate::borrow::TryToOwned;
6use crate::clone::TryClone;
7use crate::error::Error;
8use crate::{Box, Vec};
9
10cfg_if! {
11    if #[cfg(rune_nightly)] {
12        pub(crate) use core::slice::range;
13    } else {
14        use core::ops;
15
16        #[must_use]
17        pub(crate) fn range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize>
18        where
19            R: ops::RangeBounds<usize>,
20        {
21            let len = bounds.end;
22
23            let start: ops::Bound<&usize> = range.start_bound();
24            let start = match start {
25                ops::Bound::Included(&start) => start,
26                ops::Bound::Excluded(start) => start
27                    .checked_add(1)
28                    .unwrap_or_else(|| slice_start_index_overflow_fail()),
29                ops::Bound::Unbounded => 0,
30            };
31
32            let end: ops::Bound<&usize> = range.end_bound();
33            let end = match end {
34                ops::Bound::Included(end) => end
35                    .checked_add(1)
36                    .unwrap_or_else(|| slice_end_index_overflow_fail()),
37                ops::Bound::Excluded(&end) => end,
38                ops::Bound::Unbounded => len,
39            };
40
41            if start > end {
42                slice_index_order_fail(start, end);
43            }
44            if end > len {
45                slice_end_index_len_fail(end, len);
46            }
47
48            ops::Range { start, end }
49        }
50
51        const fn slice_start_index_overflow_fail() -> ! {
52            panic!("attempted to index slice from after maximum usize");
53        }
54
55        const fn slice_end_index_overflow_fail() -> ! {
56            panic!("attempted to index slice up to maximum usize");
57        }
58
59        fn slice_index_order_fail(index: usize, end: usize) -> ! {
60            panic!("slice index starts at {index} but ends at {end}");
61        }
62
63        fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
64            panic!("range end index {index} out of range for slice of length {len}");
65        }
66    }
67}
68
69/// Converts `self` into a vector without clones or allocation.
70///
71/// The resulting vector can be converted back into a box via
72/// `Vec<T>`'s `into_boxed_slice` method.
73#[inline]
74#[doc(hidden)]
75pub fn into_vec<T, A>(this: Box<[T], A>) -> Vec<T, A>
76where
77    A: Allocator,
78{
79    // N.B., see the `hack` module in this file for more details.
80    hack::into_vec(this)
81}
82
83#[inline]
84pub(crate) fn to_vec<T, A>(s: &[T], alloc: A) -> Result<Vec<T, A>, Error>
85where
86    T: TryClone,
87    A: Allocator,
88{
89    hack::to_vec(s, alloc)
90}
91
92impl<T> TryToOwned for [T]
93where
94    T: TryClone,
95{
96    type Owned = Vec<T, Global>;
97
98    #[inline]
99    fn try_to_owned(&self) -> Result<Self::Owned, Error> {
100        hack::to_vec(self, Global)
101    }
102}
103
104// HACK(japaric): With cfg(test) `impl [T]` is not available, these three
105// functions are actually methods that are in `impl [T]` but not in
106// `core::slice::SliceExt` - we need to supply these functions for the
107// `test_permutations` test
108pub(crate) mod hack {
109    use crate::alloc::Allocator;
110    use crate::clone::TryClone;
111    use crate::error::Error;
112    use crate::{Box, Vec};
113
114    // We shouldn't add inline attribute to this since this is used in `vec!`
115    // macro mostly and causes perf regression. See #71204 for discussion and
116    // perf results.
117    pub(crate) fn into_vec<T, A>(b: Box<[T], A>) -> Vec<T, A>
118    where
119        A: Allocator,
120    {
121        unsafe {
122            let len = b.len();
123            let (b, alloc) = Box::into_raw_with_allocator(b);
124            Vec::from_raw_parts_in(b as *mut T, len, len, alloc)
125        }
126    }
127
128    #[inline]
129    pub(crate) fn to_vec<T, A>(s: &[T], alloc: A) -> Result<Vec<T, A>, Error>
130    where
131        T: ConvertVec,
132        A: Allocator,
133    {
134        T::to_vec(s, alloc)
135    }
136
137    pub(crate) trait ConvertVec {
138        fn to_vec<A>(s: &[Self], alloc: A) -> Result<Vec<Self, A>, Error>
139        where
140            Self: Sized,
141            A: Allocator;
142    }
143
144    impl<T> ConvertVec for T
145    where
146        T: TryClone,
147    {
148        default_fn! {
149            #[inline]
150            fn to_vec<A>(s: &[Self], alloc: A) -> Result<Vec<Self, A>, Error>
151            where
152                A: Allocator,
153            {
154                struct DropGuard<'a, T, A>
155                where
156                    A: Allocator,
157                {
158                    vec: &'a mut Vec<T, A>,
159                    num_init: usize,
160                }
161
162                impl<T, A> Drop for DropGuard<'_, T, A>
163                where
164                    A: Allocator,
165                {
166                    #[inline]
167                    fn drop(&mut self) {
168                        // SAFETY:
169                        // items were marked initialized in the loop below
170                        unsafe {
171                            self.vec.set_len(self.num_init);
172                        }
173                    }
174                }
175
176                let mut vec = Vec::try_with_capacity_in(s.len(), alloc)?;
177                let mut guard = DropGuard {
178                    vec: &mut vec,
179                    num_init: 0,
180                };
181                let slots = guard.vec.spare_capacity_mut();
182                // .take(slots.len()) is necessary for LLVM to remove bounds checks
183                // and has better codegen than zip.
184                for (i, b) in s.iter().enumerate().take(slots.len()) {
185                    guard.num_init = i;
186                    slots[i].write(b.try_clone()?);
187                }
188                core::mem::forget(guard);
189                // SAFETY:
190                // the vec was allocated and initialized above to at least this length.
191                unsafe {
192                    vec.set_len(s.len());
193                }
194                Ok(vec)
195            }
196        }
197    }
198
199    #[cfg(rune_nightly)]
200    impl<T: crate::clone::TryCopy> ConvertVec for T {
201        #[inline]
202        fn to_vec<A>(s: &[Self], alloc: A) -> Result<Vec<Self, A>, Error>
203        where
204            A: Allocator,
205        {
206            let mut v = Vec::try_with_capacity_in(s.len(), alloc)?;
207
208            // SAFETY:
209            // allocated above with the capacity of `s`, and initialize to `s.len()` in
210            // ptr::copy_to_non_overlapping below.
211            unsafe {
212                s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len());
213                v.set_len(s.len());
214            }
215            Ok(v)
216        }
217    }
218}