typed_index_collections/slice/
slice_index.rs

1use core::ops;
2
3use crate::{TiRangeBounds, TiSlice};
4
5mod 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
35pub 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
78impl<K, V> TiSliceIndex<K, V> for K
79where
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        // SAFETY: Guaranteed by the caller.
97        unsafe { slice.raw.get_unchecked(usize::from(self)) }
98    }
99
100    #[inline]
101    unsafe fn get_unchecked_mut(self, slice: &mut TiSlice<K, V>) -> &mut Self::Output {
102        // SAFETY: Guaranteed by the caller.
103        unsafe { slice.raw.get_unchecked_mut(usize::from(self)) }
104    }
105
106    #[inline]
107    fn index(self, slice: &TiSlice<K, V>) -> &Self::Output {
108        &slice.raw[usize::from(self)]
109    }
110
111    #[inline]
112    fn index_mut(self, slice: &mut TiSlice<K, V>) -> &mut Self::Output {
113        &mut slice.raw[usize::from(self)]
114    }
115}
116
117macro_rules! impl_ti_slice_range {
118    ($ty:ty) => {
119        impl<K, V> TiSliceIndex<K, V> for $ty
120        where
121            usize: From<K>,
122        {
123            type Output = TiSlice<K, V>;
124
125            #[inline]
126            fn get(self, slice: &TiSlice<K, V>) -> Option<&Self::Output> {
127                slice.raw.get(self.into_range()).map(TiSlice::from_ref)
128            }
129
130            #[inline]
131            fn get_mut(self, slice: &mut TiSlice<K, V>) -> Option<&mut Self::Output> {
132                slice.raw.get_mut(self.into_range()).map(TiSlice::from_mut)
133            }
134
135            #[inline]
136            unsafe fn get_unchecked(self, slice: &TiSlice<K, V>) -> &Self::Output {
137                // SAFETY: Guaranteed by the caller.
138                TiSlice::from_ref(unsafe { slice.raw.get_unchecked(self.into_range()) })
139            }
140
141            #[inline]
142            unsafe fn get_unchecked_mut(self, slice: &mut TiSlice<K, V>) -> &mut Self::Output {
143                // SAFETY: Guaranteed by the caller.
144                TiSlice::from_mut(unsafe { slice.raw.get_unchecked_mut(self.into_range()) })
145            }
146
147            #[inline]
148            fn index(self, slice: &TiSlice<K, V>) -> &Self::Output {
149                TiSlice::from_ref(&slice.raw[self.into_range()])
150            }
151
152            #[inline]
153            fn index_mut(self, slice: &mut TiSlice<K, V>) -> &mut Self::Output {
154                TiSlice::from_mut(&mut slice.raw[self.into_range()])
155            }
156        }
157    };
158}
159
160impl_ti_slice_range!(ops::Range<K>);
161impl_ti_slice_range!(ops::RangeFrom<K>);
162impl_ti_slice_range!(ops::RangeInclusive<K>);
163impl_ti_slice_range!(ops::RangeTo<K>);
164impl_ti_slice_range!(ops::RangeToInclusive<K>);
165impl_ti_slice_range!((ops::Bound<K>, ops::Bound<K>));