generic_str/
slice_utf32_index.rs

1use core::slice::SliceIndex;
2
3use crate::string_base::StringBase;
4
5/// Implements substring slicing with syntax `&self[..]` or `&mut self[..]`.
6///
7/// Returns a slice of the whole string, i.e., returns `&self` or `&mut
8/// self`. Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. Unlike
9/// other indexing operations, this can never panic.
10///
11/// This operation is *O*(1).
12///
13/// Prior to 1.20.0, these indexing operations were still supported by
14/// direct implementation of `Index` and `IndexMut`.
15///
16/// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`.
17unsafe impl SliceIndex<StringBase<[char]>> for core::ops::RangeFull {
18    type Output = StringBase<[char]>;
19    #[inline]
20    fn get(self, slice: &StringBase<[char]>) -> Option<&Self::Output> {
21        Some(slice)
22    }
23    #[inline]
24    fn get_mut(self, slice: &mut StringBase<[char]>) -> Option<&mut Self::Output> {
25        Some(slice)
26    }
27    #[inline]
28    unsafe fn get_unchecked(self, slice: *const StringBase<[char]>) -> *const Self::Output {
29        slice
30    }
31    #[inline]
32    unsafe fn get_unchecked_mut(self, slice: *mut StringBase<[char]>) -> *mut Self::Output {
33        slice
34    }
35    #[inline]
36    fn index(self, slice: &StringBase<[char]>) -> &Self::Output {
37        slice
38    }
39    #[inline]
40    fn index_mut(self, slice: &mut StringBase<[char]>) -> &mut Self::Output {
41        slice
42    }
43}
44
45/// Implements substring slicing with syntax `&self[begin .. end]` or `&mut
46/// self[begin .. end]`.
47///
48/// Returns a slice of the given string from the byte range
49/// [`begin`, `end`).
50///
51/// This operation is *O*(1).
52///
53/// Prior to 1.20.0, these indexing operations were still supported by
54/// direct implementation of `Index` and `IndexMut`.
55///
56/// # Panics
57///
58/// Panics if `begin > end`, or if `end > len`.
59unsafe impl SliceIndex<StringBase<[char]>> for core::ops::Range<usize> {
60    type Output = StringBase<[char]>;
61    #[inline]
62    fn get(self, slice: &StringBase<[char]>) -> Option<&Self::Output> {
63        if self.start <= self.end && self.end <= slice.len() {
64            Some(unsafe { &*self.get_unchecked(slice) })
65        } else {
66            None
67        }
68    }
69    #[inline]
70    fn get_mut(self, slice: &mut StringBase<[char]>) -> Option<&mut Self::Output> {
71        if self.start <= self.end && self.end <= slice.len() {
72            // SAFETY: just checked that `start` and `end` are on a char boundary.
73            // We know the pointer is unique because we got it from `slice`.
74            Some(unsafe { &mut *self.get_unchecked_mut(slice) })
75        } else {
76            None
77        }
78    }
79    #[inline]
80    unsafe fn get_unchecked(self, slice: *const StringBase<[char]>) -> *const Self::Output {
81        let slice = slice as *const [char];
82        // SAFETY: the caller guarantees that `self` is in bounds of `slice`
83        // which satisfies all the conditions for `add`.
84        let ptr = slice.as_ptr().add(self.start);
85        let len = self.end - self.start;
86        core::ptr::slice_from_raw_parts(ptr, len) as *const StringBase<[char]>
87    }
88    #[inline]
89    unsafe fn get_unchecked_mut(self, slice: *mut StringBase<[char]>) -> *mut Self::Output {
90        let slice = slice as *mut [char];
91        // SAFETY: see comments for `get_unchecked`.
92        let ptr = slice.as_mut_ptr().add(self.start);
93        let len = self.end - self.start;
94        core::ptr::slice_from_raw_parts_mut(ptr, len) as *mut StringBase<[char]>
95    }
96    #[inline]
97    fn index(self, slice: &StringBase<[char]>) -> &Self::Output {
98        let end = self.end;
99        match self.get(slice) {
100            Some(s) => s,
101
102            #[cfg(feature = "alloc")]
103            None => panic!("char index {} is out of bounds of `{}`", end, &*slice),
104
105            #[cfg(not(feature = "alloc"))]
106            None => panic!("char index {} is out of bounds", end),
107        }
108    }
109    #[inline]
110    fn index_mut(self, slice: &mut StringBase<[char]>) -> &mut Self::Output {
111        if self.start <= self.end && self.end <= slice.len() {
112            // SAFETY: just checked that `start` and `end` are on a char boundary.
113            // We know the pointer is unique because we got it from `slice`.
114            unsafe { &mut *self.get_unchecked_mut(slice) }
115        } else {
116            #[cfg(feature = "alloc")]
117            panic!("char index {} is out of bounds of `{}`", self.end, &*slice);
118
119            #[cfg(not(feature = "alloc"))]
120            panic!("char index {} is out of bounds", self.end);
121        }
122    }
123}
124
125/// Implements substring slicing with syntax `&self[.. end]` or `&mut
126/// self[.. end]`.
127///
128/// Returns a slice of the given string from the char range [`0`, `end`).
129/// Equivalent to `&self[0 .. end]` or `&mut self[0 .. end]`.
130///
131/// This operation is *O*(1).
132///
133/// Prior to 1.20.0, these indexing operations were still supported by
134/// direct implementation of `Index` and `IndexMut`.
135///
136/// # Panics
137///
138/// Panics if `end > len`.
139unsafe impl SliceIndex<StringBase<[char]>> for core::ops::RangeTo<usize> {
140    type Output = StringBase<[char]>;
141    #[inline]
142    fn get(self, slice: &StringBase<[char]>) -> Option<&Self::Output> {
143        if self.end <= slice.len() {
144            // SAFETY: just checked that `end` is on a char boundary,
145            // and we are passing in a safe reference, so the return value will also be one.
146            Some(unsafe { &*self.get_unchecked(slice) })
147        } else {
148            None
149        }
150    }
151    #[inline]
152    fn get_mut(self, slice: &mut StringBase<[char]>) -> Option<&mut Self::Output> {
153        if self.end <= slice.len() {
154            // SAFETY: just checked that `end` is on a char boundary,
155            // and we are passing in a safe reference, so the return value will also be one.
156            Some(unsafe { &mut *self.get_unchecked_mut(slice) })
157        } else {
158            None
159        }
160    }
161    #[inline]
162    unsafe fn get_unchecked(self, slice: *const StringBase<[char]>) -> *const Self::Output {
163        let slice = slice as *const [char];
164        let ptr = slice.as_ptr();
165        core::ptr::slice_from_raw_parts(ptr, self.end) as *const StringBase<[char]>
166    }
167    #[inline]
168    unsafe fn get_unchecked_mut(self, slice: *mut StringBase<[char]>) -> *mut Self::Output {
169        let slice = slice as *mut [char];
170        let ptr = slice.as_mut_ptr();
171        core::ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut StringBase<[char]>
172    }
173    #[inline]
174    fn index(self, slice: &StringBase<[char]>) -> &Self::Output {
175        let end = self.end;
176        match self.get(slice) {
177            Some(s) => s,
178
179            #[cfg(feature = "alloc")]
180            None => panic!("char index {} is out of bounds of `{}`", end, &*slice),
181
182            #[cfg(not(feature = "alloc"))]
183            None => panic!("char index {} is out of bounds", end),
184        }
185    }
186    #[inline]
187    fn index_mut(self, slice: &mut StringBase<[char]>) -> &mut Self::Output {
188        if self.end <= slice.len() {
189            // SAFETY: just checked that `end` is on a char boundary,
190            // and we are passing in a safe reference, so the return value will also be one.
191            unsafe { &mut *self.get_unchecked_mut(slice) }
192        } else {
193            #[cfg(feature = "alloc")]
194            panic!("char index {} is out of bounds of `{}`", self.end, &*slice);
195
196            #[cfg(not(feature = "alloc"))]
197            panic!("char index {} is out of bounds", self.end);
198        }
199    }
200}
201
202/// Implements substring slicing with syntax `&self[begin ..]` or `&mut
203/// self[begin ..]`.
204///
205/// Returns a slice of the given string from the char range [`begin`,
206/// `len`). Equivalent to `&self[begin .. len]` or `&mut self[begin ..
207/// len]`.
208///
209/// This operation is *O*(1).
210///
211/// Prior to 1.20.0, these indexing operations were still supported by
212/// direct implementation of `Index` and `IndexMut`.
213///
214/// # Panics
215///
216/// Panics if `begin > len`.
217unsafe impl SliceIndex<StringBase<[char]>> for core::ops::RangeFrom<usize> {
218    type Output = StringBase<[char]>;
219    #[inline]
220    fn get(self, slice: &StringBase<[char]>) -> Option<&Self::Output> {
221        if self.start <= slice.len() {
222            // SAFETY: just checked that `start` is on a char boundary,
223            // and we are passing in a safe reference, so the return value will also be one.
224            Some(unsafe { &*self.get_unchecked(slice) })
225        } else {
226            None
227        }
228    }
229    #[inline]
230    fn get_mut(self, slice: &mut StringBase<[char]>) -> Option<&mut Self::Output> {
231        if self.start <= slice.len() {
232            // SAFETY: just checked that `start` is on a char boundary,
233            // and we are passing in a safe reference, so the return value will also be one.
234            Some(unsafe { &mut *self.get_unchecked_mut(slice) })
235        } else {
236            None
237        }
238    }
239    #[inline]
240    unsafe fn get_unchecked(self, slice: *const StringBase<[char]>) -> *const Self::Output {
241        let slice = slice as *const [char];
242        // SAFETY: the caller guarantees that `self` is in bounds of `slice`
243        // which satisfies all the conditions for `add`.
244        let ptr = slice.as_ptr().add(self.start);
245        let len = slice.len() - self.start;
246        core::ptr::slice_from_raw_parts(ptr, len) as *const StringBase<[char]>
247    }
248    #[inline]
249    unsafe fn get_unchecked_mut(self, slice: *mut StringBase<[char]>) -> *mut Self::Output {
250        let slice = slice as *mut [char];
251        // SAFETY: identical to `get_unchecked`.
252        let ptr = slice.as_mut_ptr().add(self.start);
253        let len = slice.len() - self.start;
254        core::ptr::slice_from_raw_parts_mut(ptr, len) as *mut StringBase<[char]>
255    }
256    #[inline]
257    fn index(self, slice: &StringBase<[char]>) -> &Self::Output {
258        let start = self.start;
259        match self.get(slice) {
260            Some(s) => s,
261
262            #[cfg(feature = "alloc")]
263            None => panic!("char index {} is out of bounds of `{}`", start, &*slice),
264
265            #[cfg(not(feature = "alloc"))]
266            None => panic!("char index {} is out of bounds", start),
267        }
268    }
269    #[inline]
270    fn index_mut(self, slice: &mut StringBase<[char]>) -> &mut Self::Output {
271        if self.start <= slice.len() {
272            // SAFETY: just checked that `start` is on a char boundary,
273            // and we are passing in a safe reference, so the return value will also be one.
274            unsafe { &mut *self.get_unchecked_mut(slice) }
275        } else {
276            #[cfg(feature = "alloc")]
277            panic!(
278                "char index {} is out of bounds of `{}`",
279                self.start, &*slice
280            );
281
282            #[cfg(not(feature = "alloc"))]
283            panic!("char index {} is out of bounds", self.start);
284        }
285    }
286}
287
288/// Implements substring slicing with syntax `&self[..= end]` or `&mut
289/// self[..= end]`.
290///
291/// Returns a slice of the given string from the byte range [0, `end`].
292/// Equivalent to `&self [0 .. end + 1]`, except if `end` has the maximum
293/// value for `usize`.
294///
295/// This operation is *O*(1).
296///
297/// # Panics
298///
299/// Panics if `end` does not point to the ending byte offset of a character
300/// (`end + 1` is either a starting byte offset as defined by
301/// `is_char_boundary`, or equal to `len`), or if `end >= len`.
302unsafe impl SliceIndex<StringBase<[char]>> for core::ops::RangeToInclusive<usize> {
303    type Output = StringBase<[char]>;
304    #[inline]
305    fn get(self, slice: &StringBase<[char]>) -> Option<&Self::Output> {
306        if self.end == usize::MAX {
307            None
308        } else {
309            (..self.end + 1).get(slice)
310        }
311    }
312    #[inline]
313    fn get_mut(self, slice: &mut StringBase<[char]>) -> Option<&mut Self::Output> {
314        if self.end == usize::MAX {
315            None
316        } else {
317            (..self.end + 1).get_mut(slice)
318        }
319    }
320    #[inline]
321    unsafe fn get_unchecked(self, slice: *const StringBase<[char]>) -> *const Self::Output {
322        // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
323        (..self.end + 1).get_unchecked(slice)
324    }
325    #[inline]
326    unsafe fn get_unchecked_mut(self, slice: *mut StringBase<[char]>) -> *mut Self::Output {
327        // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
328        (..self.end + 1).get_unchecked_mut(slice)
329    }
330    #[inline]
331    fn index(self, slice: &StringBase<[char]>) -> &Self::Output {
332        if self.end == usize::MAX {
333            str_index_overflow_fail();
334        }
335        (..self.end + 1).index(slice)
336    }
337    #[inline]
338    fn index_mut(self, slice: &mut StringBase<[char]>) -> &mut Self::Output {
339        if self.end == usize::MAX {
340            str_index_overflow_fail();
341        }
342        (..self.end + 1).index_mut(slice)
343    }
344}
345
346#[inline(never)]
347#[cold]
348#[track_caller]
349fn str_index_overflow_fail() -> ! {
350    panic!("attempted to index str up to maximum usize");
351}