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}