| 1 | use core::ops; |
| 2 | |
| 3 | use crate::{TiRangeBounds, TiSlice}; |
| 4 | |
| 5 | mod private { |
| 6 | use core::ops; |
| 7 | |
| 8 | pub trait Sealed<K> {} |
| 9 | |
| 10 | impl<K> Sealed<K> for K {} |
| 11 | impl<K> Sealed<K> for ops::Range<K> {} |
| 12 | impl<K> Sealed<K> for ops::RangeTo<K> {} |
| 13 | impl<K> Sealed<K> for ops::RangeFrom<K> {} |
| 14 | impl<K> Sealed<K> for ops::RangeInclusive<K> {} |
| 15 | impl<K> Sealed<K> for ops::RangeToInclusive<K> {} |
| 16 | impl<K> Sealed<K> for (ops::Bound<K>, ops::Bound<K>) {} |
| 17 | } |
| 18 | |
| 19 | /// A helper trait used for indexing operations. |
| 20 | /// |
| 21 | /// This trait is implemented for `K`, [`Range<K>`], [`RangeTo<K>`], |
| 22 | /// [`RangeFrom<K>`], [`RangeInclusive<K>`] and [`RangeToInclusive<K>`]. |
| 23 | /// The [`RangeFull<K>`] trait is not currently supported. |
| 24 | /// |
| 25 | /// Trait implementations are only forwards to standard Rust [`slice`] |
| 26 | /// operations. |
| 27 | /// |
| 28 | /// [`slice`]: https://doc.rust-lang.org/std/primitive.slice.html |
| 29 | /// [`Range<K>`]: https://doc.rust-lang.org/std/ops/struct.Range.html |
| 30 | /// [`RangeTo<K>`]: https://doc.rust-lang.org/std/ops/struct.RangeTo.html |
| 31 | /// [`RangeFrom<K>`]: https://doc.rust-lang.org/std/ops/struct.RangeFrom.html |
| 32 | /// [`RangeInclusive<K>`]: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html |
| 33 | /// [`RangeToInclusive<K>`]: https://doc.rust-lang.org/std/ops/struct.RangeToInclusive.html |
| 34 | /// [`RangeFull<K>`]: https://doc.rust-lang.org/std/ops/struct.RangeFull.html |
| 35 | pub trait TiSliceIndex<K, V>: private::Sealed<K> { |
| 36 | /// The output type returned by methods. |
| 37 | type Output: ?Sized; |
| 38 | |
| 39 | /// Returns a shared reference to the output at this location, if in |
| 40 | /// bounds. |
| 41 | fn get(self, slice: &TiSlice<K, V>) -> Option<&Self::Output>; |
| 42 | |
| 43 | /// Returns a mutable reference to the output at this location, if in |
| 44 | /// bounds. |
| 45 | fn get_mut(self, slice: &mut TiSlice<K, V>) -> Option<&mut Self::Output>; |
| 46 | |
| 47 | /// Returns a shared reference to the output at this location, without |
| 48 | /// performing any bounds checking. |
| 49 | /// |
| 50 | /// # Safety |
| 51 | /// |
| 52 | /// Calling this method with an out-of-bounds index is |
| 53 | /// *[undefined behavior]* even if the resulting reference is not used. |
| 54 | /// |
| 55 | /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html |
| 56 | unsafe fn get_unchecked(self, slice: &TiSlice<K, V>) -> &Self::Output; |
| 57 | |
| 58 | /// Returns a mutable reference to the output at this location, without |
| 59 | /// performing any bounds checking. |
| 60 | /// |
| 61 | /// # Safety |
| 62 | /// |
| 63 | /// Calling this method with an out-of-bounds index is |
| 64 | /// *[undefined behavior]* even if the resulting reference is not used. |
| 65 | /// |
| 66 | /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html |
| 67 | unsafe fn get_unchecked_mut(self, slice: &mut TiSlice<K, V>) -> &mut Self::Output; |
| 68 | |
| 69 | /// Returns a shared reference to the output at this location, panicking |
| 70 | /// if out of bounds. |
| 71 | fn index(self, slice: &TiSlice<K, V>) -> &Self::Output; |
| 72 | |
| 73 | /// Returns a mutable reference to the output at this location, panicking |
| 74 | /// if out of bounds. |
| 75 | fn index_mut(self, slice: &mut TiSlice<K, V>) -> &mut Self::Output; |
| 76 | } |
| 77 | |
| 78 | impl<K, V> TiSliceIndex<K, V> for K |
| 79 | where |
| 80 | usize: From<K>, |
| 81 | { |
| 82 | type Output = V; |
| 83 | |
| 84 | #[inline ] |
| 85 | fn get(self, slice: &TiSlice<K, V>) -> Option<&Self::Output> { |
| 86 | slice.raw.get(usize::from(self)) |
| 87 | } |
| 88 | |
| 89 | #[inline ] |
| 90 | fn get_mut(self, slice: &mut TiSlice<K, V>) -> Option<&mut Self::Output> { |
| 91 | slice.raw.get_mut(usize::from(self)) |
| 92 | } |
| 93 | |
| 94 | #[inline ] |
| 95 | unsafe fn get_unchecked(self, slice: &TiSlice<K, V>) -> &Self::Output { |
| 96 | slice.raw.get_unchecked(usize::from(self)) |
| 97 | } |
| 98 | |
| 99 | #[inline ] |
| 100 | unsafe fn get_unchecked_mut(self, slice: &mut TiSlice<K, V>) -> &mut Self::Output { |
| 101 | slice.raw.get_unchecked_mut(usize::from(self)) |
| 102 | } |
| 103 | |
| 104 | #[inline ] |
| 105 | fn index(self, slice: &TiSlice<K, V>) -> &Self::Output { |
| 106 | &slice.raw[usize::from(self)] |
| 107 | } |
| 108 | |
| 109 | #[inline ] |
| 110 | fn index_mut(self, slice: &mut TiSlice<K, V>) -> &mut Self::Output { |
| 111 | &mut slice.raw[usize::from(self)] |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | macro_rules! impl_ti_slice_range { |
| 116 | ($ty:ty) => { |
| 117 | impl<K, V> TiSliceIndex<K, V> for $ty |
| 118 | where |
| 119 | usize: From<K>, |
| 120 | { |
| 121 | type Output = TiSlice<K, V>; |
| 122 | |
| 123 | #[inline] |
| 124 | fn get(self, slice: &TiSlice<K, V>) -> Option<&Self::Output> { |
| 125 | slice.raw.get(self.into_range()).map(TiSlice::from_ref) |
| 126 | } |
| 127 | |
| 128 | #[inline] |
| 129 | fn get_mut(self, slice: &mut TiSlice<K, V>) -> Option<&mut Self::Output> { |
| 130 | slice.raw.get_mut(self.into_range()).map(TiSlice::from_mut) |
| 131 | } |
| 132 | |
| 133 | #[inline] |
| 134 | unsafe fn get_unchecked(self, slice: &TiSlice<K, V>) -> &Self::Output { |
| 135 | TiSlice::from_ref(slice.raw.get_unchecked(self.into_range())) |
| 136 | } |
| 137 | |
| 138 | #[inline] |
| 139 | unsafe fn get_unchecked_mut(self, slice: &mut TiSlice<K, V>) -> &mut Self::Output { |
| 140 | TiSlice::from_mut(slice.raw.get_unchecked_mut(self.into_range())) |
| 141 | } |
| 142 | |
| 143 | #[inline] |
| 144 | fn index(self, slice: &TiSlice<K, V>) -> &Self::Output { |
| 145 | TiSlice::from_ref(&slice.raw[self.into_range()]) |
| 146 | } |
| 147 | |
| 148 | #[inline] |
| 149 | fn index_mut(self, slice: &mut TiSlice<K, V>) -> &mut Self::Output { |
| 150 | TiSlice::from_mut(&mut slice.raw[self.into_range()]) |
| 151 | } |
| 152 | } |
| 153 | }; |
| 154 | } |
| 155 | |
| 156 | impl_ti_slice_range!(ops::Range<K>); |
| 157 | impl_ti_slice_range!(ops::RangeFrom<K>); |
| 158 | impl_ti_slice_range!(ops::RangeInclusive<K>); |
| 159 | impl_ti_slice_range!(ops::RangeTo<K>); |
| 160 | impl_ti_slice_range!(ops::RangeToInclusive<K>); |
| 161 | impl_ti_slice_range!((ops::Bound<K>, ops::Bound<K>)); |
| 162 | |