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: Allocator>(this: Box<[T], A>) -> Vec<T, A> {
76    // N.B., see the `hack` module in this file for more details.
77    hack::into_vec(this)
78}
79
80#[inline]
81pub(crate) fn to_vec<T, A: Allocator>(s: &[T], alloc: A) -> Result<Vec<T, A>, Error>
82where
83    T: TryClone,
84{
85    hack::to_vec(s, alloc)
86}
87
88impl<T> TryToOwned for [T]
89where
90    T: TryClone,
91{
92    type Owned = Vec<T, Global>;
93
94    #[inline]
95    fn try_to_owned(&self) -> Result<Self::Owned, Error> {
96        hack::to_vec(self, Global)
97    }
98}
99
100// HACK(japaric): With cfg(test) `impl [T]` is not available, these three
101// functions are actually methods that are in `impl [T]` but not in
102// `core::slice::SliceExt` - we need to supply these functions for the
103// `test_permutations` test
104pub(crate) mod hack {
105    use crate::alloc::Allocator;
106    use crate::clone::TryClone;
107    use crate::error::Error;
108    use crate::{Box, Vec};
109
110    // We shouldn't add inline attribute to this since this is used in `vec!`
111    // macro mostly and causes perf regression. See #71204 for discussion and
112    // perf results.
113    pub(crate) fn into_vec<T, A: Allocator>(b: Box<[T], A>) -> Vec<T, A> {
114        unsafe {
115            let len = b.len();
116            let (b, alloc) = Box::into_raw_with_allocator(b);
117            Vec::from_raw_parts_in(b as *mut T, len, len, alloc)
118        }
119    }
120
121    #[inline]
122    pub(crate) fn to_vec<T: ConvertVec, A: Allocator>(
123        s: &[T],
124        alloc: A,
125    ) -> Result<Vec<T, A>, Error> {
126        T::to_vec(s, alloc)
127    }
128
129    pub(crate) trait ConvertVec {
130        fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Result<Vec<Self, A>, Error>
131        where
132            Self: Sized;
133    }
134
135    impl<T> ConvertVec for T
136    where
137        T: TryClone,
138    {
139        default_fn! {
140            #[inline]
141            fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Result<Vec<Self, A>, Error> {
142                struct DropGuard<'a, T, A: Allocator> {
143                    vec: &'a mut Vec<T, A>,
144                    num_init: usize,
145                }
146
147                impl<T, A: Allocator> Drop for DropGuard<'_, T, A> {
148                    #[inline]
149                    fn drop(&mut self) {
150                        // SAFETY:
151                        // items were marked initialized in the loop below
152                        unsafe {
153                            self.vec.set_len(self.num_init);
154                        }
155                    }
156                }
157                let mut vec = Vec::try_with_capacity_in(s.len(), alloc)?;
158                let mut guard = DropGuard {
159                    vec: &mut vec,
160                    num_init: 0,
161                };
162                let slots = guard.vec.spare_capacity_mut();
163                // .take(slots.len()) is necessary for LLVM to remove bounds checks
164                // and has better codegen than zip.
165                for (i, b) in s.iter().enumerate().take(slots.len()) {
166                    guard.num_init = i;
167                    slots[i].write(b.try_clone()?);
168                }
169                core::mem::forget(guard);
170                // SAFETY:
171                // the vec was allocated and initialized above to at least this length.
172                unsafe {
173                    vec.set_len(s.len());
174                }
175                Ok(vec)
176            }
177        }
178    }
179
180    #[cfg(rune_nightly)]
181    impl<T: crate::clone::TryCopy> ConvertVec for T {
182        #[inline]
183        fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Result<Vec<Self, A>, Error> {
184            let mut v = Vec::try_with_capacity_in(s.len(), alloc)?;
185
186            // SAFETY:
187            // allocated above with the capacity of `s`, and initialize to `s.len()` in
188            // ptr::copy_to_non_overlapping below.
189            unsafe {
190                s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len());
191                v.set_len(s.len());
192            }
193            Ok(v)
194        }
195    }
196}