slice_utils/
slicing.rs

1use core::marker::PhantomData;
2use core::ops::{Bound, RangeBounds};
3
4use crate::{Slice, SliceBorrowed, SliceMut, SliceOwned, Unique};
5
6/// A sub-slice of a [`Slice`]; see [`Slice::slice`].
7#[derive(Clone, Copy, Hash)]
8pub struct SliceOf<A> {
9    data: A,
10
11    start: Bound<usize>,
12    len: usize,
13}
14
15impl<A> SliceOf<A>
16where
17    A: Slice,
18{
19    /// Creates a sub-slice; see [`Slice::slice`].
20    pub fn new<R: RangeBounds<usize>>(data: A, range: R) -> Option<Self> {
21        let start = match range.start_bound().cloned() {
22            s @ Bound::Included(_) | s @ Bound::Excluded(_) => s,
23            Bound::Unbounded => Bound::Included(0),
24        };
25
26        let end = match range.end_bound().cloned() {
27            e @ Bound::Included(_) | e @ Bound::Excluded(_) => e,
28            Bound::Unbounded => Bound::Included(data.len() - 1),
29        };
30
31        // TODO: make this work
32        // if end > data.len() {
33        //     return None;
34        // }
35
36        match (start, end) {
37            (Bound::Included(s), Bound::Included(e)) if s > e || e >= data.len() => None,
38            (Bound::Included(s), Bound::Excluded(e)) if s > e || e > data.len() => None,
39            (Bound::Excluded(s), Bound::Included(e)) if s > e || e >= data.len() => None,
40            (Bound::Excluded(s), Bound::Excluded(e)) if s > e || e > data.len() => None,
41
42            _ => Some(Self {
43                data,
44                start,
45                len: match (start, end) {
46                    (Bound::Included(s), Bound::Included(e)) => e - s + 1,
47                    (Bound::Included(s), Bound::Excluded(e)) => e - s,
48                    (Bound::Excluded(s), Bound::Included(e)) => e - s,
49                    (Bound::Excluded(s), Bound::Excluded(e)) => e - s - 1,
50                    _ => unreachable!(),
51                },
52            }),
53        }
54    }
55}
56
57impl<A> Slice for SliceOf<A>
58where
59    A: Slice,
60{
61    type Output = A::Output;
62
63    fn len(&self) -> usize {
64        self.len
65    }
66
67    fn get_with<W: FnMut(&Self::Output) -> R, R>(&self, index: usize, f: &mut W) -> Option<R> {
68        if index > self.len() {
69            None
70        } else {
71            self.data.get_with(
72                match self.start {
73                    Bound::Included(s) => index + s,
74                    Bound::Excluded(s) => index + s + 1,
75                    _ => unreachable!(),
76                },
77                f,
78            )
79        }
80    }
81}
82
83impl<A> SliceOwned for SliceOf<A>
84where
85    A: SliceOwned,
86{
87    fn get_owned(&self, index: usize) -> Option<Self::Output> {
88        if index > self.len() {
89            None
90        } else {
91            self.data.get_owned(match self.start {
92                Bound::Included(s) => index + s,
93                Bound::Excluded(s) => index + s + 1,
94                _ => unreachable!(),
95            })
96        }
97    }
98}
99
100impl<A> SliceBorrowed for SliceOf<A>
101where
102    A: SliceBorrowed,
103{
104    fn get(&self, index: usize) -> Option<&Self::Output> {
105        if index > self.len() {
106            None
107        } else {
108            self.data.get(match self.start {
109                Bound::Included(s) => index + s,
110                Bound::Excluded(s) => index + s + 1,
111                _ => unreachable!(),
112            })
113        }
114    }
115}
116
117impl<A> SliceMut for SliceOf<A>
118where
119    A: SliceMut,
120{
121    fn get_mut(&mut self, index: usize) -> Option<&mut Self::Output> {
122        if index > self.len() {
123            None
124        } else {
125            self.data.get_mut(match self.start {
126                Bound::Included(s) => index + s,
127                Bound::Excluded(s) => index + s + 1,
128                _ => unreachable!(),
129            })
130        }
131    }
132}
133
134// SAFETY: the underlying slice is `Unique` and owned
135unsafe impl<A> Unique for SliceOf<A> where A: Unique {}
136
137/// A mutable sub-slice of a [`Slice`]; see [`SliceMut::split_mut`].
138#[derive(Clone, Copy, Hash)]
139pub struct SplitMut<'a, A: ?Sized> {
140    data: *mut A,
141
142    start: Bound<usize>,
143    len: usize,
144
145    _lifetime: PhantomData<&'a mut A>,
146}
147
148impl<A> SplitMut<'_, A>
149where
150    A: Slice + ?Sized,
151{
152    /// Creates a mutable split of the slice; see [`SliceMut::split_mut`].
153    pub fn new(data: &mut A, at: usize) -> Option<(Self, Self)> {
154        let len = data.len();
155        if at >= len {
156            None
157        } else {
158            Some((
159                Self {
160                    data: data as *mut A,
161
162                    start: Bound::Included(0),
163                    len: at + 1,
164
165                    _lifetime: PhantomData,
166                },
167                Self {
168                    data: data as *mut A,
169
170                    start: Bound::Excluded(at),
171                    len: len - at - 1,
172
173                    _lifetime: PhantomData,
174                },
175            ))
176        }
177    }
178
179    fn data_imm(&self) -> &A {
180        // SAFETY: lifetimes are guaranteed, `Unique` ensures no aliasing
181        unsafe { &*self.data }
182    }
183
184    fn data_mut(&mut self) -> &mut A {
185        // SAFETY: lifetimes are guaranteed, `Unique` ensures no aliasing
186        unsafe { &mut *self.data }
187    }
188}
189
190impl<A> Slice for SplitMut<'_, A>
191where
192    A: Slice + ?Sized,
193{
194    type Output = A::Output;
195
196    fn len(&self) -> usize {
197        self.len
198    }
199
200    fn get_with<W: FnMut(&Self::Output) -> R, R>(&self, index: usize, f: &mut W) -> Option<R> {
201        if index > self.len() {
202            None
203        } else {
204            self.data_imm().get_with(
205                match self.start {
206                    Bound::Included(s) => index + s,
207                    Bound::Excluded(s) => index + s + 1,
208                    _ => unreachable!(),
209                },
210                f,
211            )
212        }
213    }
214}
215
216impl<A> SliceBorrowed for SplitMut<'_, A>
217where
218    A: SliceBorrowed + ?Sized,
219{
220    fn get(&self, index: usize) -> Option<&Self::Output> {
221        let i = match self.start {
222            Bound::Included(s) => index + s,
223            Bound::Excluded(s) => index + s + 1,
224            _ => unreachable!(),
225        };
226
227        if index > self.len {
228            None
229        } else {
230            self.data_imm().get(i)
231        }
232    }
233}
234
235impl<A> SliceOwned for SplitMut<'_, A>
236where
237    A: SliceOwned + ?Sized,
238{
239    fn get_owned(&self, index: usize) -> Option<Self::Output> {
240        let i = match self.start {
241            Bound::Included(s) => index + s,
242            Bound::Excluded(s) => index + s + 1,
243            _ => unreachable!(),
244        };
245
246        if index > self.len {
247            None
248        } else {
249            self.data_imm().get_owned(i)
250        }
251    }
252}
253
254impl<A> SliceMut for SplitMut<'_, A>
255where
256    A: SliceMut + Unique,
257{
258    fn get_mut(&mut self, index: usize) -> Option<&mut Self::Output> {
259        let i = match self.start {
260            Bound::Included(s) => index + s,
261            Bound::Excluded(s) => index + s + 1,
262            _ => unreachable!(),
263        };
264
265        if index > self.len() {
266            None
267        } else {
268            self.data_mut().get_mut(i)
269        }
270    }
271}