mini_io_queue/
region.rs

1use core::ops::{Bound, Index, IndexMut, Range, RangeBounds};
2
3/// A region of two separate slices that represent continuous data.
4///
5/// [`Ring`] implements a "ring-buffer", meaning the left and right regions can overlap the ends of
6/// the underlying buffer, causing them to be split into two contiguous slices (chunks). `Region`
7/// represents these two chunks, allowing their data to be accessed mostly like one continuous slice
8/// without allocations or copies.
9///
10/// [`Ring`]: crate::Ring
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub struct Region<'a, T>(&'a [T], &'a [T]);
13
14impl<'a, T> Region<'a, T> {
15    /// Creates a region with two slices.
16    ///
17    /// The slices should represent continuous data, where `slice_0` goes before `slice_1`.
18    #[inline]
19    pub fn new(slice_0: &'a [T], slice_1: &'a [T]) -> Self {
20        Region(slice_0, slice_1)
21    }
22
23    /// Returns `true` if the region has a length of 0.
24    #[inline]
25    pub fn is_empty(&self) -> bool {
26        self.0.is_empty() && self.1.is_empty()
27    }
28
29    /// Returns the number of elements in the region.
30    #[inline]
31    pub fn len(&self) -> usize {
32        self.0.len() + self.1.len()
33    }
34
35    /// Returns an iterator over the region.
36    ///
37    /// The iterator yields all items from start to end.
38    pub fn iter(&self) -> impl Iterator<Item = &'a T> + 'a {
39        [self.0.iter(), self.1.iter()].into_iter().flatten()
40    }
41
42    /// Returns the first contiguous slice in the region.
43    ///
44    /// The slice will not necessarily contain all data in the region. If the region is not empty,
45    /// the slice is guaranteed to contain some data.
46    #[inline]
47    pub fn contiguous(&self) -> &'a [T] {
48        if self.0.is_empty() {
49            self.1
50        } else {
51            self.0
52        }
53    }
54
55    /// Slices the region, returning a new region containing a part of the original.
56    ///
57    /// # Panics
58    /// Panics if the `start` or `end` of the range is `>= region.len()`.
59    pub fn slice<R>(&self, range: R) -> Self
60    where
61        R: RangeBounds<usize>,
62    {
63        let (range_0, range_1) = self.slice_ranges(range);
64
65        let slice_0 = &self.0[range_0];
66        let slice_1 = &self.1[range_1];
67
68        Region(slice_0, slice_1)
69    }
70
71    fn slice_ranges<R>(&self, range: R) -> (Range<usize>, Range<usize>)
72    where
73        R: RangeBounds<usize>,
74    {
75        let start_inclusive = match range.start_bound() {
76            Bound::Included(v) => *v,
77            Bound::Excluded(v) => v.saturating_add(1),
78            Bound::Unbounded => 0,
79        };
80        let end_exclusive = match range.end_bound() {
81            Bound::Included(v) => v.saturating_add(1),
82            Bound::Excluded(v) => *v,
83            Bound::Unbounded => self.len(),
84        };
85
86        let mid = self.0.len();
87        let slice_0 = start_inclusive.min(mid)..end_exclusive.min(mid);
88        let slice_1 = (start_inclusive - slice_0.start)..(end_exclusive - slice_0.end);
89
90        (slice_0, slice_1)
91    }
92}
93
94impl<'a, T> Region<'a, T>
95where
96    T: Copy,
97{
98    /// Copies all elements in the region into `dest`, using a memcpy.
99    ///
100    /// The length of `dest` must be the same as `self`.
101    ///
102    /// If `T` does not implement `Copy`, use [`clone_to_slice`].
103    ///
104    /// # Panics
105    /// This function will panic if `dest` has a different length to `self`.
106    ///
107    /// [`clone_to_slice`]: Region::clone_to_slice
108    pub fn copy_to_slice(&self, dest: &mut [T]) {
109        assert_eq!(
110            self.len(),
111            dest.len(),
112            "destination and source slices have different lengths"
113        );
114
115        let (dest_0, dest_1) = dest.split_at_mut(self.0.len());
116        dest_0.copy_from_slice(self.0);
117        dest_1.copy_from_slice(self.1);
118    }
119}
120
121impl<'a, T> Region<'a, T>
122where
123    T: Clone,
124{
125    /// Copies all elements in the region into `dest`.
126    ///
127    /// The length of `dest` must be the same as `self`.
128    ///
129    /// # Panics
130    /// This function will panic if `dest` has a different length to `self`.
131    pub fn clone_to_slice(&self, dest: &mut [T]) {
132        assert_eq!(
133            self.len(),
134            dest.len(),
135            "destination and source slices have different lengths"
136        );
137
138        let (dest_0, dest_1) = dest.split_at_mut(self.0.len());
139        dest_0.clone_from_slice(self.0);
140        dest_1.clone_from_slice(self.1);
141    }
142}
143
144impl<'a, T> Default for Region<'a, T> {
145    #[inline]
146    fn default() -> Self {
147        Region(Default::default(), Default::default())
148    }
149}
150
151impl<'a, T> Index<usize> for Region<'a, T> {
152    type Output = T;
153
154    fn index(&self, index: usize) -> &Self::Output {
155        if index >= self.0.len() {
156            &self.1[index - self.0.len()]
157        } else {
158            &self.0[index]
159        }
160    }
161}
162
163/// A region of two separate mutable slices that represent continuous data.
164///
165/// This is the mutable equivalent to [`Region`], allowing mutable access to the contained slices.
166///
167/// [`Region`]: crate::Region
168#[derive(Debug, PartialEq, Eq, Hash)]
169pub struct RegionMut<'a, T>(&'a mut [T], &'a mut [T]);
170
171impl<'a, T> RegionMut<'a, T> {
172    /// Creates a region with two mutable slices.
173    ///
174    /// The slices should represent continuous data, where `slice_0` goes before `slice_1`.
175    #[inline]
176    pub fn new(slice_0: &'a mut [T], slice_1: &'a mut [T]) -> Self {
177        RegionMut(slice_0, slice_1)
178    }
179
180    /// Returns a non-mutable version of the region.
181    #[inline]
182    pub fn as_ref(&self) -> Region<T> {
183        Region(self.0, self.1)
184    }
185
186    /// Returns `true` if the region has a length of 0.
187    #[inline]
188    pub fn is_empty(&self) -> bool {
189        self.as_ref().is_empty()
190    }
191
192    /// Returns the number of elements in the region.
193    #[inline]
194    pub fn len(&self) -> usize {
195        self.as_ref().len()
196    }
197
198    /// Returns an iterator over the region.
199    ///
200    /// The iterator yields all items from start to end.
201    #[inline]
202    pub fn iter(&self) -> impl Iterator<Item = &T> {
203        self.as_ref().iter()
204    }
205
206    /// Returns an iterator that allows modifying each value.
207    ///
208    /// The iterator yields all items from start to end.
209    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
210        [self.0.iter_mut(), self.1.iter_mut()].into_iter().flatten()
211    }
212
213    /// Returns the first contiguous slice in the region.
214    ///
215    /// The slice will not necessarily contain all data in the region.
216    #[inline]
217    pub fn contiguous(&self) -> &[T] {
218        self.as_ref().contiguous()
219    }
220
221    /// Returns a mutable reference to the first contiguous slice in the region.
222    ///
223    /// The slice will not necessarily contain all data in the region.
224    #[inline]
225    pub fn contiguous_mut(&mut self) -> &mut [T] {
226        if self.0.is_empty() {
227            self.1
228        } else {
229            self.0
230        }
231    }
232
233    /// Slices the region, returning a new region containing a part of the original.
234    ///
235    /// # Panics
236    /// Panics if the `start` or `end` of the range is `>= region.len()`.
237    #[inline]
238    pub fn slice<R>(&self, range: R) -> Region<T>
239    where
240        R: RangeBounds<usize>,
241    {
242        self.as_ref().slice(range)
243    }
244
245    /// Slices the region, returning a new mutable region containing a part of the original.
246    ///
247    /// # Panics
248    /// Panics if the `start` or `end` of the range is `>= region.len()`.
249    pub fn slice_mut<R>(&mut self, range: R) -> RegionMut<T>
250    where
251        R: RangeBounds<usize>,
252    {
253        let (range_0, range_1) = self.as_ref().slice_ranges(range);
254
255        let slice_0 = &mut self.0[range_0];
256        let slice_1 = &mut self.1[range_1];
257
258        RegionMut(slice_0, slice_1)
259    }
260}
261
262impl<'a, T> RegionMut<'a, T>
263where
264    T: Copy,
265{
266    /// Copies all elements in the region into `dest`, using a memcpy.
267    ///
268    /// The length of `dest` must be the same as `self`.
269    ///
270    /// If `T` does not implement `Copy`, use [`clone_to_slice`].
271    ///
272    /// # Panics
273    /// This function will panic if `dest` has a different length to `self`.
274    ///
275    /// [`clone_to_slice`]: RegionMut::clone_to_slice
276    #[inline]
277    pub fn copy_to_slice(&self, slice: &mut [T]) {
278        self.as_ref().copy_to_slice(slice)
279    }
280
281    /// Copies all elements from `src` into the region, using a memcpy.
282    ///
283    /// The length of `src` must be the same as `self`.
284    ///
285    /// If `T` does not implement `Copy`, use [`clone_from_slice`].
286    ///
287    /// # Panics
288    /// This function will panic if `src` has a different length to `self`.
289    ///
290    /// [`clone_from_slice`]: RegionMut::clone_from_slice
291    pub fn copy_from_slice(&mut self, src: &[T]) {
292        assert_eq!(
293            self.len(),
294            src.len(),
295            "destination and source slices have different lengths"
296        );
297
298        let (src_0, src_1) = src.split_at(self.0.len());
299        self.0.copy_from_slice(src_0);
300        self.1.copy_from_slice(src_1);
301    }
302}
303
304impl<'a, T> RegionMut<'a, T>
305where
306    T: Clone,
307{
308    /// Copies all elements in the region into `dest`.
309    ///
310    /// The length of `dest` must be the same as `self`.
311    ///
312    /// # Panics
313    /// This function will panic if `dest` has a different length to `self`.
314    #[inline]
315    pub fn clone_to_slice(&self, slice: &mut [T]) {
316        self.as_ref().clone_to_slice(slice)
317    }
318
319    /// Copies all elements from `src` into the region.
320    ///
321    /// The length of `src` must be the same as `self`.
322    ///
323    /// # Panics
324    /// This function will panic if `src` has a different length to `self`.
325    pub fn clone_from_slice(&mut self, src: &[T]) {
326        assert_eq!(
327            self.len(),
328            src.len(),
329            "destination and source slices have different lengths"
330        );
331
332        let (src_0, src_1) = src.split_at(self.0.len());
333        self.0.clone_from_slice(src_0);
334        self.1.clone_from_slice(src_1);
335    }
336}
337
338impl<'a, T> Default for RegionMut<'a, T> {
339    #[inline]
340    fn default() -> Self {
341        RegionMut(Default::default(), Default::default())
342    }
343}
344
345impl<'a, T> Index<usize> for RegionMut<'a, T> {
346    type Output = T;
347
348    fn index(&self, index: usize) -> &Self::Output {
349        if index >= self.0.len() {
350            &self.1[index - self.0.len()]
351        } else {
352            &self.0[index]
353        }
354    }
355}
356
357impl<'a, T> IndexMut<usize> for RegionMut<'a, T> {
358    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
359        if index >= self.0.len() {
360            &mut self.1[index - self.0.len()]
361        } else {
362            &mut self.0[index]
363        }
364    }
365}
366
367#[cfg(test)]
368mod tests {
369    use crate::{Region, RegionMut};
370
371    fn collect<T: Clone>(region: &Region<T>) -> Vec<T> {
372        region.iter().cloned().collect()
373    }
374
375    #[test]
376    fn region_default_is_empty() {
377        assert!(Region::<u8>::default().is_empty());
378        assert_eq!(Region::<u8>::default().len(), 0);
379    }
380
381    #[test]
382    fn region_is_empty() {
383        let empty_arr = [];
384        let full_arr = [1, 2, 3];
385
386        assert!(Region::new(&empty_arr, &empty_arr).is_empty());
387        assert!(!Region::new(&full_arr, &full_arr).is_empty());
388        assert!(!Region::new(&full_arr, &empty_arr).is_empty());
389        assert!(!Region::new(&empty_arr, &full_arr).is_empty());
390    }
391
392    #[test]
393    fn region_len() {
394        let empty_arr = [];
395        let full_arr = [1, 2, 3];
396
397        assert_eq!(Region::new(&empty_arr, &empty_arr).len(), 0);
398        assert_eq!(Region::new(&full_arr, &full_arr).len(), 6);
399        assert_eq!(Region::new(&full_arr, &empty_arr).len(), 3);
400        assert_eq!(Region::new(&empty_arr, &full_arr).len(), 3);
401    }
402
403    #[test]
404    fn region_iter() {
405        let empty_arr = [];
406        let arr_1 = [1, 2, 3];
407        let arr_2 = [4, 5, 6];
408
409        assert_eq!(
410            Region::new(&empty_arr, &empty_arr)
411                .iter()
412                .cloned()
413                .collect::<Vec<_>>(),
414            vec![]
415        );
416        assert_eq!(
417            Region::new(&arr_1, &arr_2)
418                .iter()
419                .cloned()
420                .collect::<Vec<_>>(),
421            vec![1, 2, 3, 4, 5, 6]
422        );
423        assert_eq!(
424            Region::new(&arr_1, &empty_arr)
425                .iter()
426                .cloned()
427                .collect::<Vec<_>>(),
428            vec![1, 2, 3]
429        );
430        assert_eq!(
431            Region::new(&empty_arr, &arr_2)
432                .iter()
433                .cloned()
434                .collect::<Vec<_>>(),
435            vec![4, 5, 6]
436        );
437    }
438
439    #[test]
440    fn region_contiguous() {
441        let empty_arr = [];
442        let arr_1 = [1, 2, 3];
443        let arr_2 = [4, 5, 6];
444
445        assert!(Region::new(&empty_arr, &empty_arr).contiguous().is_empty());
446        assert_eq!(Region::new(&arr_1, &arr_2).contiguous(), [1, 2, 3]);
447        assert_eq!(Region::new(&arr_1, &empty_arr).contiguous(), [1, 2, 3]);
448        assert_eq!(Region::new(&empty_arr, &arr_2).contiguous(), [4, 5, 6]);
449    }
450
451    #[test]
452    fn region_slice() {
453        let arr_1 = [1, 2, 3];
454        let arr_2 = [4, 5, 6];
455        let region = Region::new(&arr_1, &arr_2);
456
457        assert_eq!(collect(&region.slice(..)), vec![1, 2, 3, 4, 5, 6]);
458        assert_eq!(collect(&region.slice(1..)), vec![2, 3, 4, 5, 6]);
459        assert_eq!(collect(&region.slice(3..)), vec![4, 5, 6]);
460        assert_eq!(collect(&region.slice(5..)), vec![6]);
461        assert_eq!(collect(&region.slice(6..)), vec![]);
462        assert_eq!(collect(&region.slice(..5)), vec![1, 2, 3, 4, 5]);
463        assert_eq!(collect(&region.slice(..3)), vec![1, 2, 3]);
464        assert_eq!(collect(&region.slice(..1)), vec![1]);
465        assert_eq!(collect(&region.slice(..0)), vec![]);
466        assert_eq!(collect(&region.slice(..=5)), vec![1, 2, 3, 4, 5, 6]);
467        assert_eq!(collect(&region.slice(1..3)), vec![2, 3]);
468        assert_eq!(collect(&region.slice(2..4)), vec![3, 4]);
469        assert_eq!(collect(&region.slice(3..5)), vec![4, 5]);
470        assert_eq!(collect(&region.slice(0..6)), vec![1, 2, 3, 4, 5, 6]);
471    }
472
473    #[test]
474    fn region_copy_to_slice() {
475        let arr_1 = [1, 2, 3];
476        let arr_2 = [4, 5, 6];
477        let region = Region::new(&arr_1, &arr_2);
478
479        let mut dest = [0, 0, 0, 0, 0, 0];
480        region.copy_to_slice(&mut dest);
481
482        assert_eq!(dest, [1, 2, 3, 4, 5, 6]);
483    }
484
485    #[test]
486    fn region_clone_to_slice() {
487        let arr_1 = [1, 2, 3];
488        let arr_2 = [4, 5, 6];
489        let region = Region::new(&arr_1, &arr_2);
490
491        let mut dest = [0, 0, 0, 0, 0, 0];
492        region.clone_to_slice(&mut dest);
493
494        assert_eq!(dest, [1, 2, 3, 4, 5, 6]);
495    }
496
497    #[test]
498    fn region_index() {
499        let arr_1 = [1, 2, 3];
500        let arr_2 = [4, 5, 6];
501        let region = Region::new(&arr_1, &arr_2);
502
503        assert_eq!(region[0], 1);
504        assert_eq!(region[2], 3);
505        assert_eq!(region[4], 5);
506    }
507
508    #[test]
509    fn region_mut_as_ref() {
510        let mut arr_1 = [1, 2, 3];
511        let mut arr_2 = [4, 5, 6];
512        let region = RegionMut::new(&mut arr_1, &mut arr_2);
513
514        assert_eq!(collect(&region.as_ref()), vec![1, 2, 3, 4, 5, 6]);
515    }
516
517    #[test]
518    fn region_mut_copy_from_slice() {
519        let mut arr_1 = [1, 2, 3];
520        let mut arr_2 = [4, 5, 6];
521        let mut region = RegionMut::new(&mut arr_1, &mut arr_2);
522
523        let src = [100, 101, 102, 103, 104, 105];
524        region.copy_from_slice(&src);
525
526        assert_eq!(
527            collect(&region.as_ref()),
528            vec![100, 101, 102, 103, 104, 105]
529        );
530        assert_eq!(region.contiguous(), [100, 101, 102]);
531    }
532
533    #[test]
534    fn region_mut_clone_from_slice() {
535        let mut arr_1 = [1, 2, 3];
536        let mut arr_2 = [4, 5, 6];
537        let mut region = RegionMut::new(&mut arr_1, &mut arr_2);
538
539        let src = [100, 101, 102, 103, 104, 105];
540        region.clone_from_slice(&src);
541
542        assert_eq!(
543            collect(&region.as_ref()),
544            vec![100, 101, 102, 103, 104, 105]
545        );
546        assert_eq!(region.contiguous(), [100, 101, 102]);
547    }
548
549    #[test]
550    fn region_mut_index() {
551        let mut arr_1 = [1, 2, 3];
552        let mut arr_2 = [4, 5, 6];
553        let mut region = RegionMut::new(&mut arr_1, &mut arr_2);
554
555        region[1] = 100;
556        region[3] = 200;
557        region[5] = 300;
558
559        assert_eq!(collect(&region.as_ref()), vec![1, 100, 3, 200, 5, 300]);
560    }
561}