1 use std::ops::{Bound, Range, RangeBounds}; 2 3 /// An owned window around an underlying buffer. 4 /// 5 /// Normally slices work great for considering sub-portions of a buffer, but 6 /// unfortunately a slice is a *borrowed* type in Rust which has an associated 7 /// lifetime. When working with future and async I/O these lifetimes are not 8 /// always appropriate, and are sometimes difficult to store in tasks. This 9 /// type strives to fill this gap by providing an "owned slice" around an 10 /// underlying buffer of bytes. 11 /// 12 /// A `Window<T>` wraps an underlying buffer, `T`, and has configurable 13 /// start/end indexes to alter the behavior of the `AsRef<[u8]>` implementation 14 /// that this type carries. 15 /// 16 /// This type can be particularly useful when working with the `write_all` 17 /// combinator in this crate. Data can be sliced via `Window`, consumed by 18 /// `write_all`, and then earned back once the write operation finishes through 19 /// the `into_inner` method on this type. 20 #[derive(Debug)] 21 pub struct Window<T> { 22 inner: T, 23 range: Range<usize>, 24 } 25 26 impl<T: AsRef<[u8]>> Window<T> { 27 /// Creates a new window around the buffer `t` defaulting to the entire 28 /// slice. 29 /// 30 /// Further methods can be called on the returned `Window<T>` to alter the 31 /// window into the data provided. new(t: T) -> Self32 pub fn new(t: T) -> Self { 33 Self { range: 0..t.as_ref().len(), inner: t } 34 } 35 36 /// Gets a shared reference to the underlying buffer inside of this 37 /// `Window`. get_ref(&self) -> &T38 pub fn get_ref(&self) -> &T { 39 &self.inner 40 } 41 42 /// Gets a mutable reference to the underlying buffer inside of this 43 /// `Window`. get_mut(&mut self) -> &mut T44 pub fn get_mut(&mut self) -> &mut T { 45 &mut self.inner 46 } 47 48 /// Consumes this `Window`, returning the underlying buffer. into_inner(self) -> T49 pub fn into_inner(self) -> T { 50 self.inner 51 } 52 53 /// Returns the starting index of this window into the underlying buffer 54 /// `T`. start(&self) -> usize55 pub fn start(&self) -> usize { 56 self.range.start 57 } 58 59 /// Returns the end index of this window into the underlying buffer 60 /// `T`. end(&self) -> usize61 pub fn end(&self) -> usize { 62 self.range.end 63 } 64 65 /// Changes the range of this window to the range specified. 66 /// 67 /// # Panics 68 /// 69 /// This method will panic if `range` is out of bounds for the underlying 70 /// slice or if [`start_bound()`] of `range` comes after the [`end_bound()`]. 71 /// 72 /// [`start_bound()`]: std::ops::RangeBounds::start_bound 73 /// [`end_bound()`]: std::ops::RangeBounds::end_bound set<R: RangeBounds<usize>>(&mut self, range: R)74 pub fn set<R: RangeBounds<usize>>(&mut self, range: R) { 75 let start = match range.start_bound() { 76 Bound::Included(n) => *n, 77 Bound::Excluded(n) => *n + 1, 78 Bound::Unbounded => 0, 79 }; 80 let end = match range.end_bound() { 81 Bound::Included(n) => *n + 1, 82 Bound::Excluded(n) => *n, 83 Bound::Unbounded => self.inner.as_ref().len(), 84 }; 85 86 assert!(end <= self.inner.as_ref().len()); 87 assert!(start <= end); 88 89 self.range.start = start; 90 self.range.end = end; 91 } 92 } 93 94 impl<T: AsRef<[u8]>> AsRef<[u8]> for Window<T> { as_ref(&self) -> &[u8]95 fn as_ref(&self) -> &[u8] { 96 &self.inner.as_ref()[self.range.start..self.range.end] 97 } 98 } 99 100 impl<T: AsMut<[u8]>> AsMut<[u8]> for Window<T> { as_mut(&mut self) -> &mut [u8]101 fn as_mut(&mut self) -> &mut [u8] { 102 &mut self.inner.as_mut()[self.range.start..self.range.end] 103 } 104 } 105