utf16string/
slicing.rs

1//! The [`SliceIndex`] trait and implementations.
2//!
3//! This supports all slicing for [`WStr`] and [`WString`].
4
5use std::ops::{
6    Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
7};
8
9use byteorder::ByteOrder;
10
11use crate::{WStr, WString};
12
13mod private {
14    use super::*;
15
16    pub trait SealedSliceIndex {}
17
18    impl SealedSliceIndex for RangeFull {}
19    impl SealedSliceIndex for Range<usize> {}
20    impl SealedSliceIndex for RangeFrom<usize> {}
21    impl SealedSliceIndex for RangeTo<usize> {}
22    impl SealedSliceIndex for RangeInclusive<usize> {}
23    impl SealedSliceIndex for RangeToInclusive<usize> {}
24}
25/// Our own version of [`std::slice::SliceIndex`].
26///
27/// Since this is a sealed trait, we need to re-define this trait.  This trait itself is
28/// sealed as well.
29pub trait SliceIndex<T>: private::SealedSliceIndex
30where
31    T: ?Sized,
32{
33    /// The result of slicing, another slice of the same type as you started with normally.
34    type Output: ?Sized;
35
36    /// Returns a shared reference to the output at this location, if in bounds.
37    fn get(self, slice: &T) -> Option<&Self::Output>;
38
39    /// Returns a mutable reference to the output at this location, if in bounds.
40    fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>;
41
42    /// Like [`SliceIndex::get`] but without bounds checking.
43    ///
44    /// # Safety
45    ///
46    /// You must guarantee the resulting slice is valid UTF-16LE, otherwise you will get
47    /// undefined behaviour.
48    unsafe fn get_unchecked(self, slice: &T) -> &Self::Output;
49
50    /// Like [`SliceIndex::get_mut`] but without bounds checking.
51    ///
52    /// # Safety
53    ///
54    /// You must guarantee the resulting slice is valid UTF-16LE, otherwise you will get
55    /// undefined behavour.
56    unsafe fn get_unchecked_mut(self, slice: &mut T) -> &mut Self::Output;
57
58    /// Returns a shared reference to the output at this location, panicking if out of bounds.
59    fn index(self, slice: &T) -> &Self::Output;
60
61    /// Returns a mutable reference to the output at this location, panicking if out of bounds.
62    fn index_mut(self, slice: &mut T) -> &mut Self::Output;
63}
64
65/// Implments substring slicing with syntax `&self[..]` or `&mut self[..]`.
66///
67/// Unlike other implementations this can never panic.
68impl<E> SliceIndex<WStr<E>> for RangeFull
69where
70    E: ByteOrder,
71{
72    type Output = WStr<E>;
73
74    #[inline]
75    fn get(self, slice: &WStr<E>) -> Option<&Self::Output> {
76        Some(slice)
77    }
78
79    #[inline]
80    fn get_mut(self, slice: &mut WStr<E>) -> Option<&mut Self::Output> {
81        Some(slice)
82    }
83
84    #[inline]
85    unsafe fn get_unchecked(self, slice: &WStr<E>) -> &Self::Output {
86        slice
87    }
88
89    #[inline]
90    unsafe fn get_unchecked_mut(self, slice: &mut WStr<E>) -> &mut Self::Output {
91        slice
92    }
93
94    #[inline]
95    fn index(self, slice: &WStr<E>) -> &Self::Output {
96        slice
97    }
98
99    #[inline]
100    fn index_mut(self, slice: &mut WStr<E>) -> &mut Self::Output {
101        slice
102    }
103}
104
105/// Implements substring slicing with syntax `&self[begin .. end]` or `&mut self[begin .. end]`.
106impl<E> SliceIndex<WStr<E>> for Range<usize>
107where
108    E: ByteOrder,
109{
110    type Output = WStr<E>;
111
112    #[inline]
113    fn get(self, slice: &WStr<E>) -> Option<&Self::Output> {
114        if self.start <= self.end
115            && slice.is_char_boundary(self.start)
116            && slice.is_char_boundary(self.end)
117        {
118            Some(unsafe { self.get_unchecked(slice) })
119        } else {
120            None
121        }
122    }
123
124    #[inline]
125    fn get_mut(self, slice: &mut WStr<E>) -> Option<&mut Self::Output> {
126        if self.start <= self.end
127            && slice.is_char_boundary(self.start)
128            && slice.is_char_boundary(self.end)
129        {
130            Some(unsafe { self.get_unchecked_mut(slice) })
131        } else {
132            None
133        }
134    }
135
136    #[inline]
137    unsafe fn get_unchecked(self, slice: &WStr<E>) -> &Self::Output {
138        let ptr = slice.as_ptr().add(self.start);
139        let len = self.end - self.start;
140        WStr::from_utf16_unchecked(std::slice::from_raw_parts(ptr, len))
141    }
142
143    #[inline]
144    unsafe fn get_unchecked_mut(self, slice: &mut WStr<E>) -> &mut Self::Output {
145        let ptr = slice.as_mut_ptr().add(self.start);
146        let len = self.end - self.start;
147        WStr::from_utf16_unchecked_mut(std::slice::from_raw_parts_mut(ptr, len))
148    }
149
150    #[inline]
151    fn index(self, slice: &WStr<E>) -> &Self::Output {
152        self.get(slice).expect("slice index out of bounds")
153    }
154
155    #[inline]
156    fn index_mut(self, slice: &mut WStr<E>) -> &mut Self::Output {
157        self.get_mut(slice).expect("slice index out of bounds")
158    }
159}
160
161/// Implements substring slicing with syntax `&self[.. end]` or `&mut self[.. end]`.
162impl<E> SliceIndex<WStr<E>> for RangeTo<usize>
163where
164    E: ByteOrder,
165{
166    type Output = WStr<E>;
167
168    #[inline]
169    fn get(self, slice: &WStr<E>) -> Option<&Self::Output> {
170        if slice.is_char_boundary(self.end) {
171            Some(unsafe { self.get_unchecked(slice) })
172        } else {
173            None
174        }
175    }
176
177    #[inline]
178    fn get_mut(self, slice: &mut WStr<E>) -> Option<&mut Self::Output> {
179        if slice.is_char_boundary(self.end) {
180            Some(unsafe { self.get_unchecked_mut(slice) })
181        } else {
182            None
183        }
184    }
185
186    #[inline]
187    unsafe fn get_unchecked(self, slice: &WStr<E>) -> &Self::Output {
188        let ptr = slice.as_ptr();
189        WStr::from_utf16_unchecked(std::slice::from_raw_parts(ptr, self.end))
190    }
191
192    #[inline]
193    unsafe fn get_unchecked_mut(self, slice: &mut WStr<E>) -> &mut Self::Output {
194        let ptr = slice.as_mut_ptr();
195        WStr::from_utf16_unchecked_mut(std::slice::from_raw_parts_mut(ptr, self.end))
196    }
197
198    #[inline]
199    fn index(self, slice: &WStr<E>) -> &Self::Output {
200        self.get(slice).expect("slice index out of bounds")
201    }
202
203    #[inline]
204    fn index_mut(self, slice: &mut WStr<E>) -> &mut Self::Output {
205        self.get_mut(slice).expect("slice index out of bounds")
206    }
207}
208
209/// Implements substring slicing with syntax `&self[begin ..]` or `&mut self[begin ..]`.
210impl<E> SliceIndex<WStr<E>> for RangeFrom<usize>
211where
212    E: ByteOrder,
213{
214    type Output = WStr<E>;
215
216    #[inline]
217    fn get(self, slice: &WStr<E>) -> Option<&Self::Output> {
218        if slice.is_char_boundary(self.start) {
219            Some(unsafe { self.get_unchecked(slice) })
220        } else {
221            None
222        }
223    }
224
225    #[inline]
226    fn get_mut(self, slice: &mut WStr<E>) -> Option<&mut Self::Output> {
227        if slice.is_char_boundary(self.start) {
228            Some(unsafe { self.get_unchecked_mut(slice) })
229        } else {
230            None
231        }
232    }
233
234    #[inline]
235    unsafe fn get_unchecked(self, slice: &WStr<E>) -> &Self::Output {
236        let ptr = slice.as_ptr().add(self.start);
237        let len = slice.len() - self.start;
238        WStr::from_utf16_unchecked(std::slice::from_raw_parts(ptr, len))
239    }
240
241    #[inline]
242    unsafe fn get_unchecked_mut(self, slice: &mut WStr<E>) -> &mut Self::Output {
243        let ptr = slice.as_mut_ptr().add(self.start);
244        let len = slice.len() - self.start;
245        WStr::from_utf16_unchecked_mut(std::slice::from_raw_parts_mut(ptr, len))
246    }
247
248    #[inline]
249    fn index(self, slice: &WStr<E>) -> &Self::Output {
250        self.get(slice).expect("slice index out of bounds")
251    }
252
253    #[inline]
254    fn index_mut(self, slice: &mut WStr<E>) -> &mut Self::Output {
255        self.get_mut(slice).expect("slice index out of bounds")
256    }
257}
258
259/// Implements substring slicing with syntax `&self[begin ..= end]` or `&mut self[begin ..= end]`.
260impl<E> SliceIndex<WStr<E>> for RangeInclusive<usize>
261where
262    E: ByteOrder,
263{
264    type Output = WStr<E>;
265
266    #[inline]
267    fn get(self, slice: &WStr<E>) -> Option<&Self::Output> {
268        if *self.end() == usize::MAX {
269            None
270        } else {
271            (*self.start()..self.end() + 1).get(slice)
272        }
273    }
274
275    #[inline]
276    fn get_mut(self, slice: &mut WStr<E>) -> Option<&mut Self::Output> {
277        if *self.end() == usize::MAX {
278            None
279        } else {
280            (*self.start()..self.end() + 1).get_mut(slice)
281        }
282    }
283
284    #[inline]
285    unsafe fn get_unchecked(self, slice: &WStr<E>) -> &Self::Output {
286        (*self.start()..self.end() + 1).get_unchecked(slice)
287    }
288
289    #[inline]
290    unsafe fn get_unchecked_mut(self, slice: &mut WStr<E>) -> &mut Self::Output {
291        (*self.start()..self.end() + 1).get_unchecked_mut(slice)
292    }
293
294    #[inline]
295    fn index(self, slice: &WStr<E>) -> &Self::Output {
296        if *self.end() == usize::MAX {
297            panic!("index overflow");
298        }
299        (*self.start()..self.end() + 1).index(slice)
300    }
301
302    #[inline]
303    fn index_mut(self, slice: &mut WStr<E>) -> &mut Self::Output {
304        if *self.end() == usize::MAX {
305            panic!("index overflow");
306        }
307        (*self.start()..self.end() + 1).index_mut(slice)
308    }
309}
310
311/// Implements substring slicing with syntax `&self[..= end]` or `&mut self[..= end]`.
312impl<E> SliceIndex<WStr<E>> for RangeToInclusive<usize>
313where
314    E: ByteOrder,
315{
316    type Output = WStr<E>;
317
318    #[inline]
319    fn get(self, slice: &WStr<E>) -> Option<&Self::Output> {
320        if self.end == usize::MAX {
321            None
322        } else {
323            (..self.end + 1).get(slice)
324        }
325    }
326
327    #[inline]
328    fn get_mut(self, slice: &mut WStr<E>) -> Option<&mut Self::Output> {
329        if self.end == usize::MAX {
330            None
331        } else {
332            (..self.end + 1).get_mut(slice)
333        }
334    }
335
336    #[inline]
337    unsafe fn get_unchecked(self, slice: &WStr<E>) -> &Self::Output {
338        (..self.end + 1).get_unchecked(slice)
339    }
340
341    #[inline]
342    unsafe fn get_unchecked_mut(self, slice: &mut WStr<E>) -> &mut Self::Output {
343        (..self.end + 1).get_unchecked_mut(slice)
344    }
345
346    #[inline]
347    fn index(self, slice: &WStr<E>) -> &Self::Output {
348        if self.end == usize::MAX {
349            panic!("index overflow");
350        }
351        (..self.end + 1).index(slice)
352    }
353
354    #[inline]
355    fn index_mut(self, slice: &mut WStr<E>) -> &mut Self::Output {
356        if self.end == usize::MAX {
357            panic!("index overflow");
358        }
359        (..self.end + 1).index_mut(slice)
360    }
361}
362
363impl<I, E> Index<I> for WStr<E>
364where
365    I: SliceIndex<WStr<E>>,
366    E: ByteOrder,
367{
368    type Output = I::Output;
369
370    #[inline]
371    fn index(&self, index: I) -> &I::Output {
372        index.index(self)
373    }
374}
375
376impl<I, E> IndexMut<I> for WStr<E>
377where
378    I: SliceIndex<WStr<E>>,
379    E: ByteOrder,
380{
381    #[inline]
382    fn index_mut(&mut self, index: I) -> &mut I::Output {
383        index.index_mut(self)
384    }
385}
386
387impl<I, E> Index<I> for WString<E>
388where
389    I: SliceIndex<WStr<E>>,
390    E: ByteOrder,
391{
392    type Output = I::Output;
393
394    #[inline]
395    fn index(&self, index: I) -> &I::Output {
396        index.index(self)
397    }
398}
399
400impl<I, E> IndexMut<I> for WString<E>
401where
402    I: SliceIndex<WStr<E>>,
403    E: ByteOrder,
404{
405    #[inline]
406    fn index_mut(&mut self, index: I) -> &mut I::Output {
407        index.index_mut(self)
408    }
409}
410
411#[cfg(test)]
412mod tests {
413    use super::*;
414
415    #[test]
416    fn test_wstr_range() {
417        let b = b"h\x00e\x00l\x00l\x00o\x00";
418        let s = WStr::from_utf16le(b).unwrap();
419        let t = &s[2..8];
420
421        assert_eq!(t.to_utf8(), "ell");
422    }
423
424    #[test]
425    fn test_wstr_range_to() {
426        let b = b"h\x00e\x00l\x00l\x00o\x00";
427        let s = WStr::from_utf16le(b).unwrap();
428        let t = &s[..8];
429
430        assert_eq!(t.to_utf8(), "hell");
431    }
432
433    #[test]
434    fn test_wstr_range_from() {
435        let b = b"h\x00e\x00l\x00l\x00o\x00";
436        let s = WStr::from_utf16le(b).unwrap();
437        let t = &s[2..];
438
439        assert_eq!(t.to_utf8(), "ello");
440    }
441
442    #[test]
443    fn test_wstr_range_full() {
444        let b = b"h\x00e\x00l\x00l\x00o\x00";
445        let s = WStr::from_utf16le(b).unwrap();
446        let t = &s[..];
447
448        assert_eq!(t.to_utf8(), "hello");
449    }
450
451    #[test]
452    fn test_wstr_range_inclusive() {
453        let b = b"h\x00e\x00l\x00l\x00o\x00";
454        let s = WStr::from_utf16le(b).unwrap();
455        let t = &s[2..=7];
456
457        assert_eq!(t.to_utf8(), "ell");
458    }
459
460    #[test]
461    fn test_wstr_range_to_inclusive() {
462        let b = b"h\x00e\x00l\x00l\x00o\x00";
463        let s = WStr::from_utf16le(b).unwrap();
464        let t = &s[..=7];
465
466        assert_eq!(t.to_utf8(), "hell");
467    }
468
469    #[test]
470    fn test_wstring_range() {
471        let b = b"h\x00e\x00l\x00l\x00o\x00";
472        let s = WString::from_utf16le(b.to_vec()).unwrap();
473        let t = &s[2..8];
474
475        assert_eq!(t.to_utf8(), "ell");
476    }
477
478    #[test]
479    fn test_wstring_range_to() {
480        let b = b"h\x00e\x00l\x00l\x00o\x00";
481        let s = WString::from_utf16le(b.to_vec()).unwrap();
482        let t = &s[..8];
483
484        assert_eq!(t.to_utf8(), "hell");
485    }
486
487    #[test]
488    fn test_wstring_range_from() {
489        let b = b"h\x00e\x00l\x00l\x00o\x00";
490        let s = WString::from_utf16le(b.to_vec()).unwrap();
491        let t = &s[2..];
492
493        assert_eq!(t.to_utf8(), "ello");
494    }
495
496    #[test]
497    fn test_wstring_range_full() {
498        let b = b"h\x00e\x00l\x00l\x00o\x00";
499        let s = WString::from_utf16le(b.to_vec()).unwrap();
500        let t = &s[..];
501
502        assert_eq!(t.to_utf8(), "hello");
503    }
504
505    #[test]
506    fn test_wstring_range_inclusive() {
507        let b = b"h\x00e\x00l\x00l\x00o\x00";
508        let s = WString::from_utf16le(b.to_vec()).unwrap();
509        let t = &s[2..=7];
510
511        assert_eq!(t.to_utf8(), "ell");
512    }
513
514    #[test]
515    fn test_wstring_range_to_inclusive() {
516        let b = b"h\x00e\x00l\x00l\x00o\x00";
517        let s = WString::from_utf16le(b.to_vec()).unwrap();
518        let t = &s[..=7];
519
520        assert_eq!(t.to_utf8(), "hell");
521    }
522}