@@ -81,6 +81,8 @@ mod private_slice_index {
81
81
impl Sealed for ops::RangeInclusive<usize> {}
82
82
#[stable(feature = "slice_get_slice", since = "1.28.0")]
83
83
impl Sealed for ops::RangeToInclusive<usize> {}
84
+ #[stable(feature = "slice_index_with_ops_bound_pair", since = "1.51.0")]
85
+ impl Sealed for (ops::Bound<usize>, ops::Bound<usize>) {}
84
86
}
85
87
86
88
/// A helper trait used for indexing operations.
@@ -546,3 +548,113 @@ where
546
548
547
549
ops::Range { start, end }
548
550
}
551
+
552
+ /// Convert pair of `ops::Bound`s into `ops::Range` without performing any bounds checking and (in debug) overflow checking
553
+ fn into_range_unchecked(
554
+ len: usize,
555
+ (start, end): (ops::Bound<usize>, ops::Bound<usize>),
556
+ ) -> ops::Range<usize> {
557
+ use ops::Bound;
558
+ let start = match start {
559
+ Bound::Included(i) => i,
560
+ Bound::Excluded(i) => i + 1,
561
+ Bound::Unbounded => 0,
562
+ };
563
+ let end = match end {
564
+ Bound::Included(i) => i + 1,
565
+ Bound::Excluded(i) => i,
566
+ Bound::Unbounded => len,
567
+ };
568
+ start..end
569
+ }
570
+
571
+ /// Convert pair of `ops::Bound`s into `ops::Range`.
572
+ /// Returns `None` on overflowing indices.
573
+ fn into_range(
574
+ len: usize,
575
+ (start, end): (ops::Bound<usize>, ops::Bound<usize>),
576
+ ) -> Option<ops::Range<usize>> {
577
+ use ops::Bound;
578
+ let start = match start {
579
+ Bound::Included(start) => start,
580
+ Bound::Excluded(start) => start.checked_add(1)?,
581
+ Bound::Unbounded => 0,
582
+ };
583
+
584
+ let end = match end {
585
+ Bound::Included(end) => end.checked_add(1)?,
586
+ Bound::Excluded(end) => end,
587
+ Bound::Unbounded => len,
588
+ };
589
+
590
+ // Don't bother with checking `start < end` and `end <= len`
591
+ // since these checks are handled by `Range` impls
592
+
593
+ Some(start..end)
594
+ }
595
+
596
+ /// Convert pair of `ops::Bound`s into `ops::Range`.
597
+ /// Panics on overflowing indices.
598
+ fn into_slice_range(
599
+ len: usize,
600
+ (start, end): (ops::Bound<usize>, ops::Bound<usize>),
601
+ ) -> ops::Range<usize> {
602
+ use ops::Bound;
603
+ let start = match start {
604
+ Bound::Included(start) => start,
605
+ Bound::Excluded(start) => {
606
+ start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
607
+ }
608
+ Bound::Unbounded => 0,
609
+ };
610
+
611
+ let end = match end {
612
+ Bound::Included(end) => {
613
+ end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
614
+ }
615
+ Bound::Excluded(end) => end,
616
+ Bound::Unbounded => len,
617
+ };
618
+
619
+ // Don't bother with checking `start < end` and `end <= len`
620
+ // since these checks are handled by `Range` impls
621
+
622
+ start..end
623
+ }
624
+
625
+ #[stable(feature = "slice_index_with_ops_bound_pair", since = "1.51.0")]
626
+ unsafe impl<T> SliceIndex<[T]> for (ops::Bound<usize>, ops::Bound<usize>) {
627
+ type Output = [T];
628
+
629
+ #[inline]
630
+ fn get(self, slice: &[T]) -> Option<&Self::Output> {
631
+ into_range(slice.len(), self)?.get(slice)
632
+ }
633
+
634
+ #[inline]
635
+ fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> {
636
+ into_range(slice.len(), self)?.get_mut(slice)
637
+ }
638
+
639
+ #[inline]
640
+ unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output {
641
+ // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
642
+ unsafe { into_range_unchecked(slice.len(), self).get_unchecked(slice) }
643
+ }
644
+
645
+ #[inline]
646
+ unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output {
647
+ // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
648
+ unsafe { into_range_unchecked(slice.len(), self).get_unchecked_mut(slice) }
649
+ }
650
+
651
+ #[inline]
652
+ fn index(self, slice: &[T]) -> &Self::Output {
653
+ into_slice_range(slice.len(), self).index(slice)
654
+ }
655
+
656
+ #[inline]
657
+ fn index_mut(self, slice: &mut [T]) -> &mut Self::Output {
658
+ into_slice_range(slice.len(), self).index_mut(slice)
659
+ }
660
+ }
0 commit comments