Skip to main content

packet/
fragmented.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use alloc::vec::Vec;
6use core::ops::{Range, RangeBounds};
7
8use zerocopy::{SplitByteSlice, SplitByteSliceMut};
9
10use crate::canonicalize_range;
11
12/// A wrapper for a sequence of byte slices.
13///
14/// `FragmentedByteSlice` shares its underlying memory with the slice it was
15/// constructed from and, as a result, operations on a `FragmentedByteSlice` may
16/// mutate the backing slice.
17#[derive(Debug, Eq, PartialEq)]
18pub struct FragmentedByteSlice<'a, B: SplitByteSlice>(&'a mut [B]);
19
20/// A single byte slice fragment in a [`FragmentedByteSlice`].
21pub trait Fragment: SplitByteSlice {
22    /// Takes `n` bytes from the front of this fragment.
23    ///
24    /// After a call to `take_front(n)`, the fragment is `n` bytes shorter.
25    ///
26    /// Returns `None` if `n` is larger than the length of this `ByteSlice`.
27    fn take_front(&mut self, n: usize) -> Option<Self>;
28
29    /// Takes `n` bytes from the back of this fragment.
30    ///
31    /// After a call to `take_back(n)`, the fragment is `n` bytes shorter.
32    ///
33    /// Returns `None` if `n` is larger than the length of this `ByteSlice`.
34    fn take_back(&mut self, n: usize) -> Option<Self>;
35
36    /// Constructs a new empty `Fragment`.
37    fn empty() -> Self;
38}
39
40/// A type that can produce a `FragmentedByteSlice` view of itself.
41pub trait AsFragmentedByteSlice<B: Fragment> {
42    /// Generates a `FragmentedByteSlice` view of `self`.
43    fn as_fragmented_byte_slice(&mut self) -> FragmentedByteSlice<'_, B>;
44}
45
46impl<O, B> AsFragmentedByteSlice<B> for O
47where
48    B: Fragment,
49    O: AsMut<[B]>,
50{
51    fn as_fragmented_byte_slice(&mut self) -> FragmentedByteSlice<'_, B> {
52        FragmentedByteSlice::new(self.as_mut())
53    }
54}
55
56impl<'a> Fragment for &'a [u8] {
57    fn take_front(&mut self, n: usize) -> Option<Self> {
58        self.split_off(..n)
59    }
60
61    fn take_back(&mut self, n: usize) -> Option<Self> {
62        let split = <[u8]>::len(self).checked_sub(n)?;
63        Some(self.split_off(split..).unwrap())
64    }
65
66    fn empty() -> Self {
67        &[]
68    }
69}
70
71impl<'a> Fragment for &'a mut [u8] {
72    fn take_front(&mut self, n: usize) -> Option<Self> {
73        self.split_off_mut(..n)
74    }
75
76    fn take_back(&mut self, n: usize) -> Option<Self> {
77        let split = <[u8]>::len(self).checked_sub(n)?;
78        Some(self.split_off_mut(split..).unwrap())
79    }
80
81    fn empty() -> Self {
82        &mut []
83    }
84}
85
86impl<'a, B: 'a + Fragment> FragmentedByteSlice<'a, B> {
87    /// Constructs a new `FragmentedByteSlice` from `bytes`.
88    ///
89    /// It is important to note that `FragmentedByteSlice` takes a mutable
90    /// reference to a backing slice. Operations on the `FragmentedByteSlice`
91    /// may mutate `bytes` as an optimization to avoid extra allocations.
92    ///
93    /// Users are encouraged to treat slices used to construct
94    /// `FragmentedByteSlice`s as if they are not owned anymore and only serve
95    /// as (usually temporary) backing for a `FragmentedByteSlice`.
96    pub fn new(bytes: &'a mut [B]) -> Self {
97        Self(bytes)
98    }
99
100    /// Constructs a new empty `FragmentedByteSlice`.
101    pub fn new_empty() -> Self {
102        Self(&mut [])
103    }
104
105    /// Gets the total length, in bytes, of this `FragmentedByteSlice`.
106    pub fn len(&self) -> usize {
107        // TODO(brunodalbo) explore if caching the total length in a
108        // FragmentedByteSlice could be a worthy performance optimization.
109        self.0.iter().map(|x| x.len()).sum()
110    }
111
112    /// Returns `true` if the `FragmentedByteSlice` is empty.
113    pub fn is_empty(&self) -> bool {
114        self.len() == 0
115    }
116
117    /// Slices this `FragmentedByteSlice`, reducing it to only the bytes within
118    /// `range`.
119    ///
120    /// `slice` will mutate the backing slice by dropping or shrinking fragments
121    /// as necessary so the overall composition matches the requested `range`.
122    /// The returned `FragmentedByteSlice` uses the same (albeit possibly
123    /// modified) backing mutable slice reference as `self`.
124    ///
125    /// # Panics
126    ///
127    /// Panics if the provided `range` is not within the bounds of this
128    /// `FragmentedByteSlice`, or if the range is nonsensical (the end precedes
129    /// the start).
130    pub fn slice<R>(self, range: R) -> Self
131    where
132        R: RangeBounds<usize>,
133    {
134        let len = self.len();
135        let range = canonicalize_range(len, &range);
136        let mut bytes = self.0;
137        // c is the amount of bytes we need to discard from the beginning of the
138        // fragments.
139        let mut c = range.start;
140        while c != 0 {
141            let first = &mut bytes[0];
142            if first.len() > c {
143                // if the first fragment contains more than c bytes, just take
144                // c bytes out of its front and we're done.
145                let _: B = first.take_front(c).unwrap();
146                break;
147            } else {
148                // otherwise, just account for the first fragment's entire
149                // length and drop it.
150                c -= first.len();
151                bytes = &mut bytes[1..];
152            }
153        }
154        // c is the amount of bytes we need to discard from the end of the
155        // fragments.
156        let mut c = len - range.end;
157        while c != 0 {
158            let idx = bytes.len() - 1;
159            let last = &mut bytes[idx];
160            if last.len() > c {
161                // if the last fragment contains more than c bytes, just take
162                // c bytes out of its back and we're done.
163                let _: B = last.take_back(c).unwrap();
164                break;
165            } else {
166                // otherwise, just account for the last fragment's entire length
167                // and drop it.
168                c -= last.len();
169                bytes = &mut bytes[..idx];
170            }
171        }
172        Self(bytes)
173    }
174
175    /// Checks whether the contents of this `FragmentedByteSlice` are equal to
176    /// the contents of `other`.
177    pub fn eq_slice(&self, mut other: &[u8]) -> bool {
178        for x in self.0.iter() {
179            let x = x.as_ref();
180            if other.len() < x.len() || !x.eq(&other[..x.len()]) {
181                return false;
182            }
183            other = &other[x.len()..];
184        }
185        other.is_empty()
186    }
187
188    /// Iterates over all the bytes in this `FragmentedByteSlice`.
189    pub fn iter(&self) -> impl '_ + Iterator<Item = u8> {
190        self.0.iter().map(|x| x.iter()).flatten().copied()
191    }
192
193    /// Iterates over the fragments of this `FragmentedByteSlice`.
194    pub fn iter_fragments(&'a self) -> impl 'a + Iterator<Item = &'a [u8]> + Clone {
195        self.0.iter().map(|x| x.as_ref())
196    }
197
198    /// Copies all the bytes in `self` into the contiguous slice `dst`.
199    ///
200    /// # Panics
201    ///
202    /// Panics if `dst.len() != self.len()`.
203    pub fn copy_into_slice(&self, mut dst: &mut [u8]) {
204        for p in self.0.iter() {
205            let (tgt, nxt) = dst.split_at_mut(p.len());
206            tgt.copy_from_slice(p.as_ref());
207            dst = nxt;
208        }
209        assert_eq!(dst.len(), 0);
210    }
211
212    /// Returns a flattened version of this buffer, copying its contents into a
213    /// [`Vec`].
214    pub fn to_flattened_vec(&self) -> Vec<u8> {
215        let mut out = Vec::with_capacity(self.len());
216        for x in self.0.iter() {
217            out.extend_from_slice(x);
218        }
219        out
220    }
221
222    /// Creates an index tuple from a linear index `idx`.
223    ///
224    /// `get_index` creates a tuple index `(slice, byte)` where `slice` is the
225    /// index in the backing slice of slices and `byte` is the byte index in the
226    /// slice at `self.0[slice]` where `(slice, byte)` represents the `idx`th
227    /// byte in this `FragmentedByteSlice`.
228    ///
229    /// # Panics
230    ///
231    /// Panics if `idx` is out of bounds.
232    fn get_index(&self, mut idx: usize) -> (usize, usize) {
233        let mut a = 0;
234        while self.0[a].len() <= idx || self.0[a].len() == 0 {
235            idx -= self.0[a].len();
236            a += 1;
237        }
238        (a, idx)
239    }
240
241    /// Increments the index tuple `idx`.
242    ///
243    /// Increments the index tuple `idx` (see
244    /// [`FragmentedByteSlice::get_index`]) so it references the next byte.
245    /// `increment_index` will stop incrementing and just return a slice index
246    /// equal to the length of the backing slice if `idx` can't be incremented
247    /// anymore.
248    fn increment_index(&self, idx: &mut (usize, usize)) {
249        if self.0[idx.0].len() > (idx.1 + 1) {
250            idx.1 += 1;
251        } else {
252            idx.0 += 1;
253            // skip any empty slices:
254            while idx.0 < self.0.len() && self.0[idx.0].len() == 0 {
255                idx.0 += 1;
256            }
257            idx.1 = 0;
258        }
259    }
260
261    /// Decrements the index tuple `idx`.
262    ///
263    /// Decrements the index tuple `idx` (see
264    /// [`FragmentedByteSlice::get_index`]) so it references the previous byte.
265    /// `decrement_index` will wrap around to an invalid out of bounds index
266    /// (slice index is equal to the length of the backing slice) if `idx` is
267    /// pointing to the `0`th byte.
268    fn decrement_index(&self, idx: &mut (usize, usize)) {
269        if idx.1 == 0 {
270            if idx.0 == 0 {
271                idx.0 = self.0.len();
272                idx.1 = 0;
273                return;
274            }
275            idx.0 -= 1;
276            // skip any empty slices:
277            while idx.0 != 0 && self.0[idx.0].len() == 0 {
278                idx.0 -= 1;
279            }
280            if self.0[idx.0].len() != 0 {
281                idx.1 = self.0[idx.0].len() - 1;
282            } else {
283                idx.0 = self.0.len();
284                idx.1 = 0;
285            }
286        } else {
287            idx.1 -= 1;
288        }
289    }
290
291    /// Tries to convert this `FragmentedByteSlice` into a contiguous one.
292    ///
293    /// Returns `Ok` if `self`'s backing storage contains 0 or 1 byte slices,
294    /// and `Err` otherwise.
295    ///
296    /// If `self`'s backing storage contains 1 byte slice, that byte slice will
297    /// be replaced with an empty byte slice, and the original used to construct
298    /// the return value.
299    pub fn try_into_contiguous(self) -> Result<B, Self> {
300        if self.0.is_empty() {
301            Ok(B::empty())
302        } else if self.0.len() == 1 {
303            Ok(core::mem::replace(&mut self.0[0], B::empty()))
304        } else {
305            Err(self)
306        }
307    }
308
309    /// Tries to get a contiguous reference to this `FragmentedByteSlice`.
310    ///
311    /// Returns `Some` if `self`'s backing storage contains 0 or 1 byte slices,
312    /// and `None` otherwise.
313    pub fn try_get_contiguous(&self) -> Option<&[u8]> {
314        match &self.0 {
315            [] => Some(&[]),
316            [slc] => Some(slc),
317            _ => None,
318        }
319    }
320
321    /// Tries to split this `FragmentedByteSlice` into a contiguous prefix, a
322    /// (possibly fragmented) body, and a contiguous suffix.
323    ///
324    /// Returns `None` if it isn't possible to form a contiguous prefix and
325    /// suffix with the provided `range`.
326    ///
327    /// # Panics
328    ///
329    /// Panics if the range is out of bounds, or if the range is nonsensical
330    /// (the end precedes the start).
331    pub fn try_split_contiguous<R>(self, range: R) -> Option<(B, Self, B)>
332    where
333        R: RangeBounds<usize>,
334    {
335        let len = self.len();
336        let range = canonicalize_range(len, &range);
337        if len == 0 && range.start == 0 && range.end == 0 {
338            // If own length is zero and the requested body range is an empty
339            // body start at zero, avoid returning None in the call to
340            // last_mut() below.
341            return Some((B::empty(), FragmentedByteSlice(&mut []), B::empty()));
342        }
343
344        // take foot first, because if we have a single fragment, taking head
345        // first will mess with the index calculations.
346
347        let foot = self.0.last_mut()?;
348        let take = len - range.end;
349        if foot.len() < take {
350            return None;
351        }
352        let foot = foot.take_back(take).unwrap();
353
354        let head = self.0.first_mut()?;
355        if head.len() < range.start {
356            return None;
357        }
358        let head = head.take_front(range.start).unwrap();
359
360        Some((head, self, foot))
361    }
362}
363
364impl<'a, B: 'a + SplitByteSliceMut + Fragment> FragmentedByteSlice<'a, B> {
365    /// Iterates over mutable references to all the bytes in this
366    /// `FragmentedByteSlice`.
367    pub fn iter_mut(&mut self) -> impl '_ + Iterator<Item = &'_ mut u8> {
368        self.0.iter_mut().map(|x| x.iter_mut()).flatten()
369    }
370
371    /// Copies all the bytes in `src` to `self`.
372    ///
373    /// # Panics
374    ///
375    /// Panics if `self.len() != src.len()`.
376    pub fn copy_from_slice(&mut self, mut src: &[u8]) {
377        for p in self.0.iter_mut() {
378            let (cur, nxt) = src.split_at(p.len());
379            p.as_mut().copy_from_slice(cur);
380            src = nxt;
381        }
382        assert_eq!(src.len(), 0);
383    }
384
385    /// Copies all the bytes from another `FragmentedByteSlice` `other` into
386    /// `self`.
387    ///
388    /// # Panics
389    ///
390    /// Panics if `self.len() != other.len()`.
391    pub fn copy_from<BB>(&mut self, other: &FragmentedByteSlice<'_, BB>)
392    where
393        BB: SplitByteSlice,
394    {
395        // keep an iterator over the fragments in other.
396        let mut oth = other.0.iter().map(|z| z.as_ref());
397        // op is the current fragment in other we're copying from.
398        let mut op = oth.next();
399        for part in self.0.iter_mut() {
400            // p is the current fragment in self we're feeding bytes into.
401            let mut p = part.as_mut();
402            // iterate until this fragment is all consumed.
403            while !p.is_empty() {
404                // skip any empty slices in other.
405                while op.unwrap().is_empty() {
406                    op = oth.next();
407                }
408                // get the current fragment in other.
409                let k = op.unwrap();
410                if k.len() <= p.len() {
411                    // if k does not have enough bytes to fill p, copy what we
412                    // can, change p to the region that hasn't been updated, and
413                    // then fetch the next fragment from other.
414                    let (dst, nxt) = p.split_at_mut(k.len());
415                    dst.copy_from_slice(k.as_ref());
416                    p = nxt;
417                    op = oth.next();
418                } else {
419                    // Otherwise, copy the p.len() first bytes from k, and
420                    // modify op to keep the rest of the bytes in k.
421                    let (src, nxt) = k.split_at(p.len());
422                    p.copy_from_slice(src.as_ref());
423                    op = Some(nxt);
424                    // break from loop, p had all its bytes copied.
425                    break;
426                }
427            }
428        }
429        // If anything is left in our iterator, panic if it isn't an empty slice
430        // since the lengths must match.
431        while let Some(v) = op {
432            assert_eq!(v.len(), 0);
433            op = oth.next();
434        }
435    }
436
437    /// Copies elements from one part of the `FragmentedByteSlice` to another
438    /// part of itself.
439    ///
440    /// `src` is the range within `self` to copy from. `dst` is the starting
441    /// index of the range within `self` to copy to, which will have the same
442    /// length as `src`. The two ranges may overlap. The ends of the two ranges
443    /// must be less than or equal to `self.len()`.
444    ///
445    /// # Panics
446    ///
447    /// Panics if either the source or destination range is out of bounds, or if
448    /// `src` is nonsensical (its end precedes its start).
449    pub fn copy_within<R: RangeBounds<usize>>(&mut self, src: R, dst: usize) {
450        let Range { start, end } = canonicalize_range(self.len(), &src);
451        assert!(end >= start);
452        let len = end - start;
453        if start == dst || len == 0 {
454            // no work to do
455        } else if start > dst {
456            // copy front to back
457            let mut start = self.get_index(start);
458            let mut dst = self.get_index(dst);
459            for _ in 0..len {
460                self.0[dst.0][dst.1] = self.0[start.0][start.1];
461                self.increment_index(&mut start);
462                self.increment_index(&mut dst);
463            }
464        } else {
465            // copy back to front
466            let mut start = self.get_index(end - 1);
467            let mut dst = self.get_index(dst + len - 1);
468            for _ in 0..len {
469                self.0[dst.0][dst.1] = self.0[start.0][start.1];
470                self.decrement_index(&mut start);
471                self.decrement_index(&mut dst);
472            }
473        }
474    }
475
476    /// Attempts to get a contiguous mutable reference to this
477    /// `FragmentedByteSlice`.
478    ///
479    /// Returns `Some` if this `FragmentedByteSlice` is a single contiguous part
480    /// (or is empty). Returns `None` otherwise.
481    pub fn try_get_contiguous_mut(&mut self) -> Option<&mut [u8]> {
482        match &mut self.0 {
483            [] => Some(&mut []),
484            [slc] => Some(slc),
485            _ => None,
486        }
487    }
488}
489
490/// A [`FragmentedByteSlice`] backed by immutable byte slices.
491pub type FragmentedBytes<'a, 'b> = FragmentedByteSlice<'a, &'b [u8]>;
492/// A [`FragmentedByteSlice`] backed by mutable byte slices.
493pub type FragmentedBytesMut<'a, 'b> = FragmentedByteSlice<'a, &'b mut [u8]>;
494
495#[cfg(test)]
496mod tests {
497    use super::*;
498
499    /// Calls `f` with all the possible three way slicings of a non-mutable
500    /// buffer containing `[1,2,3,4,5]` (including cases with empty slices).
501    fn with_fragments<F: for<'a, 'b> FnMut(FragmentedBytes<'a, 'b>)>(mut f: F) {
502        let buff = [1_u8, 2, 3, 4, 5];
503        for i in 0..buff.len() {
504            for j in i..buff.len() {
505                let (a, x) = buff.split_at(i);
506                let (b, c) = x.split_at(j - i);
507                let mut frags = [a, b, c];
508                f(frags.as_fragmented_byte_slice());
509            }
510        }
511    }
512
513    /// Calls `f` with all the possible three way slicings of a non-mutable
514    /// buffer containing `[1,2,3,4,5]` (including cases with empty slices).
515    fn with_fragments_mut<F: for<'a, 'b> FnMut(FragmentedBytesMut<'a, 'b>)>(mut f: F) {
516        let buff = [1_u8, 2, 3, 4, 5];
517        for i in 0..buff.len() {
518            for j in i..buff.len() {
519                let mut buff = [1_u8, 2, 3, 4, 5];
520                let (a, x) = buff.split_at_mut(i);
521                let (b, c) = x.split_at_mut(j - i);
522                let mut frags = [a, b, c];
523                f(frags.as_fragmented_byte_slice());
524            }
525        }
526    }
527
528    #[test]
529    fn test_iter() {
530        // check iterator over different fragment permutations.
531        with_fragments(|bytes| {
532            let mut iter = bytes.iter();
533            for i in 1_u8..6 {
534                assert_eq!(iter.next().unwrap(), i);
535            }
536            assert!(iter.next().is_none());
537            assert!(iter.next().is_none());
538        });
539    }
540
541    #[test]
542    fn test_eq() {
543        // check equality over different fragment permutations.
544        with_fragments(|bytes| {
545            assert!(bytes.eq_slice([1_u8, 2, 3, 4, 5].as_ref()));
546            assert!(!bytes.eq_slice([1_u8, 2, 3, 4].as_ref()));
547            assert!(!bytes.eq_slice([1_u8, 2, 3, 4, 5, 6].as_ref()));
548            assert!(!bytes.eq_slice(&[]));
549        });
550
551        // check equality for the empty slice case.
552        let bytes = FragmentedBytes::new_empty();
553        assert!(!bytes.eq_slice([1_u8, 2, 3, 4, 5].as_ref()));
554        assert!(bytes.eq_slice(&[]));
555    }
556
557    #[test]
558    fn test_slice() {
559        // test all valid ranges with all possible permutations of a three way
560        // slice.
561        for i in 0..6 {
562            for j in i..6 {
563                with_fragments(|bytes| {
564                    let range = bytes.slice(i..j);
565                    let x = [1_u8, 2, 3, 4, 5];
566                    assert_eq!(&range.to_flattened_vec()[..], &x[i..j], "{}..{}", i, j);
567                });
568            }
569        }
570    }
571
572    #[test]
573    #[should_panic]
574    fn test_slice_out_of_range() {
575        // check that slicing out of range will panic
576        with_fragments(|bytes| {
577            let _ = bytes.slice(0..15);
578        });
579    }
580
581    #[test]
582    #[should_panic]
583    fn test_copy_into_slice_too_big() {
584        // check that copy_into_slice panics for different lengths.
585        with_fragments(|bytes| {
586            let mut slice = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
587            bytes.copy_into_slice(&mut slice[..]);
588        });
589    }
590
591    #[test]
592    #[should_panic]
593    fn test_copy_into_slice_too_small() {
594        // check that copy_into_slice panics for different lengths.
595        with_fragments(|bytes| {
596            let mut slice = [1, 2];
597            bytes.copy_into_slice(&mut slice[..]);
598        });
599    }
600
601    #[test]
602    fn test_copy_into_slice() {
603        // try copy_into_slice with all different fragment permutations.
604        with_fragments(|bytes| {
605            let mut slice = [0; 5];
606            bytes.copy_into_slice(&mut slice[..]);
607            assert_eq!(slice, &[1, 2, 3, 4, 5][..]);
608        });
609    }
610
611    #[test]
612    #[should_panic]
613    fn test_copy_from_slice_too_big() {
614        // check that copy_from_slice panics for different lengths.
615        with_fragments_mut(|mut bytes| {
616            let slice = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
617            bytes.copy_from_slice(&slice[..]);
618        });
619    }
620
621    #[test]
622    #[should_panic]
623    fn test_copy_from_slice_too_small() {
624        // check that copy_from_slice panics for different lengths.
625        with_fragments_mut(|mut bytes| {
626            let slice = [1, 2, 3];
627            bytes.copy_from_slice(&slice[..]);
628        });
629    }
630
631    #[test]
632    fn test_copy_from_slice() {
633        // test copy_from_slice with all fragment permutations.
634        with_fragments_mut(|mut bytes| {
635            let slice = [10, 20, 30, 40, 50];
636            bytes.copy_from_slice(&slice[..]);
637            assert_eq!(&bytes.to_flattened_vec()[..], &slice[..]);
638        });
639    }
640
641    #[test]
642    fn test_copy_from() {
643        // test copying from another FragmentedByteSlice, going over all
644        // fragment permutations for both src and dst.
645        with_fragments(|src| {
646            with_fragments_mut(|mut dst| {
647                // zer-out dst
648                dst.copy_from_slice(&[0; 5][..]);
649                dst.copy_from(&src);
650                assert_eq!(&dst.to_flattened_vec()[..], &[1_u8, 2, 3, 4, 5][..]);
651            })
652        });
653    }
654
655    #[test]
656    #[should_panic]
657    fn test_copy_from_too_long() {
658        // copying from another FragmentedByteSlice should panic if the lengths
659        // differ.
660        let mut a = [0; 2];
661        let mut b = [0; 2];
662        let mut frags = [a.as_mut(), b.as_mut()];
663        with_fragments(|src| {
664            frags.as_fragmented_byte_slice().copy_from(&src);
665        });
666    }
667
668    #[test]
669    #[should_panic]
670    fn test_copy_from_too_short() {
671        // copying from another FragmentedByteSlice should panic if the lengths
672        // differ.
673        let mut a = [0; 5];
674        let mut b = [0; 2];
675        let mut frags = [a.as_mut(), b.as_mut()];
676        with_fragments(|src| {
677            frags.as_fragmented_byte_slice().copy_from(&src);
678        });
679    }
680
681    #[test]
682    fn test_indexing() {
683        // Test the internal indexing functions over all fragment permutations.
684        with_fragments(|bytes| {
685            for i in 0..5 {
686                // check that get_index addresses the expected byte.
687                let mut idx = bytes.get_index(i);
688                assert_eq!(bytes.0[idx.0][idx.1], (i + 1) as u8);
689
690                // check that we can increase it correctly until the end of the
691                // buffer.
692                for j in 1..(6 - i - 1) {
693                    bytes.increment_index(&mut idx);
694                    assert_eq!(bytes.0[idx.0][idx.1], (i + j + 1) as u8);
695                }
696
697                // fetch the same index again.
698                let mut idx = bytes.get_index(i);
699                assert_eq!(bytes.0[idx.0][idx.1], (i + 1) as u8);
700
701                // check that we can decrease it correctly until the beginning
702                // of the buffer.
703                for j in 1..=i {
704                    bytes.decrement_index(&mut idx);
705                    assert_eq!(bytes.0[idx.0][idx.1], (i - j + 1) as u8);
706                }
707            }
708        });
709    }
710
711    #[test]
712    fn test_copy_within() {
713        with_fragments_mut(|mut bytes| {
714            // copy last half to beginning:
715            bytes.copy_within(3..5, 0);
716            assert_eq!(&bytes.to_flattened_vec()[..], &[4, 5, 3, 4, 5]);
717        });
718        with_fragments_mut(|mut bytes| {
719            // copy first half to end:
720            bytes.copy_within(0..2, 3);
721            assert_eq!(&bytes.to_flattened_vec()[..], &[1, 2, 3, 1, 2]);
722        });
723    }
724
725    #[test]
726    #[should_panic]
727    fn test_copy_within_src_out_of_bounds() {
728        with_fragments_mut(|mut bytes| {
729            // try to copy out of bounds
730            bytes.copy_within(3..15, 0);
731        });
732    }
733
734    #[test]
735    #[should_panic]
736    fn test_copy_within_dst_out_of_bounds() {
737        with_fragments_mut(|mut bytes| {
738            // try to copy out of bounds
739            bytes.copy_within(3..5, 15);
740        });
741    }
742
743    #[test]
744    #[should_panic]
745    fn test_copy_within_bad_range() {
746        with_fragments_mut(|mut bytes| {
747            // pass a bad range (end before start)
748            #[allow(clippy::reversed_empty_ranges)]
749            bytes.copy_within(5..3, 0);
750        });
751    }
752
753    #[test]
754    fn test_get_contiguous() {
755        // If we have fragments, get_contiguous should fail:
756        with_fragments_mut(|mut bytes| {
757            assert!(bytes.try_get_contiguous().is_none());
758            assert!(bytes.try_get_contiguous_mut().is_none());
759            assert!(bytes.try_into_contiguous().is_err());
760        });
761
762        // otherwise we should be able to get the contiguous bytes:
763        let mut single = [1_u8, 2, 3, 4, 5];
764        let mut single = [&mut single[..]];
765        let mut single = single.as_fragmented_byte_slice();
766        assert_eq!(single.try_get_contiguous().unwrap(), &[1, 2, 3, 4, 5][..]);
767        assert_eq!(single.try_get_contiguous_mut().unwrap(), &[1, 2, 3, 4, 5][..]);
768        assert_eq!(single.try_into_contiguous().unwrap(), &[1, 2, 3, 4, 5][..]);
769    }
770
771    #[test]
772    fn test_split_contiguous() {
773        let data = [1_u8, 2, 3, 4, 5, 6];
774
775        // try with a single continuous slice
776        let mut refs = [&data[..]];
777        let frag = refs.as_fragmented_byte_slice();
778        let (head, body, foot) = frag.try_split_contiguous(2..4).unwrap();
779        assert_eq!(head, &data[..2]);
780        assert_eq!(&body.to_flattened_vec()[..], &data[2..4]);
781        assert_eq!(foot, &data[4..]);
782
783        // try splitting just part of the header
784        let mut refs = [&data[0..3], &data[3..]];
785        let frag = refs.as_fragmented_byte_slice();
786        let (head, body, foot) = frag.try_split_contiguous(2..6).unwrap();
787        assert_eq!(head, &data[..2]);
788        assert_eq!(&body.to_flattened_vec()[..], &data[2..]);
789        assert!(foot.is_empty());
790
791        // try splitting just part of the footer
792        let mut refs = [&data[0..3], &data[3..]];
793        let frag = refs.as_fragmented_byte_slice();
794        let (head, body, foot) = frag.try_split_contiguous(..4).unwrap();
795        assert!(head.is_empty());
796        assert_eq!(&body.to_flattened_vec()[..], &data[..4]);
797        assert_eq!(foot, &data[4..]);
798
799        // try completely extracting both:
800        let mut refs = [&data[0..3], &data[3..]];
801        let frag = refs.as_fragmented_byte_slice();
802        let (head, body, foot) = frag.try_split_contiguous(3..3).unwrap();
803        assert_eq!(head, &data[0..3]);
804        assert_eq!(body.len(), 0);
805        assert_eq!(foot, &data[3..]);
806
807        // try getting contiguous bytes from an empty FragmentedByteSlice:
808        let frag = FragmentedBytes::new_empty();
809        let (head, body, foot) = frag.try_split_contiguous(..).unwrap();
810        assert!(head.is_empty());
811        assert!(body.is_empty());
812        assert!(foot.is_empty());
813    }
814
815    #[test]
816    #[should_panic]
817    fn test_split_contiguous_out_of_bounds() {
818        let data = [1_u8, 2, 3, 4, 5, 6];
819        let mut refs = [&data[..]];
820        let frag = refs.as_fragmented_byte_slice();
821        let _ = frag.try_split_contiguous(2..8);
822    }
823
824    #[test]
825    fn test_empty() {
826        // Can create empty FragmentedByteSlices with no fragments or with one
827        // empty fragment.
828        // is_empty should return true for both cases.
829        let empty = FragmentedByteSlice::<&'static [u8]>::new_empty();
830        assert!(empty.is_empty());
831        let empty = [0_u8; 0];
832        let mut empty = [&empty[..]];
833        let empty = empty.as_fragmented_byte_slice();
834        assert!(empty.is_empty());
835    }
836}