From f81134f4d6d9cff6bde7048acd2c38039d2c36f1 Mon Sep 17 00:00:00 2001 From: oblique Date: Sat, 14 Sep 2019 13:41:08 +0300 Subject: [PATCH] Add `Buffer::resize` and `Buffer::truncate`. These methods enable users to use `Buffer` without having an intermediate array. For example: ``` let mut buffer = Buffer::with_capacity(1024); buffer.resize(1024, 0); let len = fill_some_data(buffer.buf_mut()); buffer.truncate(len); ``` --- src/buffer/mod.rs | 4 ++ src/buffer/slice_deque_buf.rs | 9 +++ src/buffer/std_buf.rs | 115 ++++++++++++++++++++++++++++++++++ src/lib.rs | 32 ++++++++++ 4 files changed, 160 insertions(+) diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 079fc70..e34cb4c 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -100,6 +100,8 @@ impl BufImpl { pub fn reserve(&mut self, additional: usize)[additional] -> bool; + pub fn resize(&mut self, new_len: usize, value: u8)[new_len, value] -> bool; + pub fn make_room(&mut self)[]; pub fn buf(&self)[] -> &[u8]; @@ -111,5 +113,7 @@ impl BufImpl { pub unsafe fn bytes_written(&mut self, add: usize)[add]; pub fn consume(&mut self, amt: usize)[amt]; + + pub fn truncate(&mut self, len: usize)[len]; } } diff --git a/src/buffer/slice_deque_buf.rs b/src/buffer/slice_deque_buf.rs index de4780b..cff6c12 100644 --- a/src/buffer/slice_deque_buf.rs +++ b/src/buffer/slice_deque_buf.rs @@ -48,6 +48,11 @@ impl SliceDequeBuf { true } + pub fn resize(&mut self, new_len: usize, value: u8) -> bool { + self.deque.resize(new_len, value); + true + } + /// This method is a no-op. pub fn make_room(&mut self) {} @@ -80,4 +85,8 @@ impl SliceDequeBuf { self.deque.move_head(offset); } } + + pub fn truncate(&mut self, len: usize) { + self.deque.truncate_back(len); + } } diff --git a/src/buffer/std_buf.rs b/src/buffer/std_buf.rs index 7e717c3..d4a0b68 100644 --- a/src/buffer/std_buf.rs +++ b/src/buffer/std_buf.rs @@ -63,6 +63,25 @@ impl StdBuf { self.buf.reserve(additional - usable_space) } + pub fn resize(&mut self, new_len: usize, value: u8) -> bool { + if new_len <= self.len() { + self.truncate(new_len); + false + } else { + let additional = new_len - self.len(); + let res = self.reserve(additional); + + unsafe { + for x in &mut self.buf.as_mut_slice()[self.end .. self.end + additional] { + *x = value; + } + } + + self.end += additional; + res + } + } + pub fn make_room(&mut self) { self.check_cursors(); @@ -104,6 +123,11 @@ impl StdBuf { self.check_cursors(); } + pub fn truncate(&mut self, len: usize) { + self.end = cmp::min(self.pos + len, self.end); + self.check_cursors(); + } + pub fn check_cursors(&mut self) -> bool { if self.pos == self.end { self.pos = 0; @@ -233,3 +257,94 @@ fn read_into_full() { assert_eq!(buffer.read_from(&mut bytes).unwrap(), 1); assert_eq!(buffer.read_from(&mut bytes).unwrap(), 0); } + +#[test] +fn test_truncate() { + use Buffer; + let mut buffer = Buffer::with_capacity(32); + + buffer.truncate(5); + assert_eq!(buffer.len(), 0); + + buffer.push_bytes(&[1, 2, 3, 4, 5, 6, 7]); + assert_eq!(buffer.len(), 7); + + buffer.truncate(10); + assert_eq!(buffer.len(), 7); + + buffer.truncate(7); + assert_eq!(buffer.len(), 7); + + buffer.truncate(5); + assert_eq!(buffer.len(), 5); + assert_eq!(buffer.buf(), &[1, 2, 3, 4, 5]); + + buffer.consume(1); + buffer.truncate(3); + assert_eq!(buffer.len(), 3); + assert_eq!(buffer.buf(), &[2, 3, 4]); + + buffer.truncate(0); + assert_eq!(buffer.len(), 0); +} + +#[test] +fn test_resize() { + use Buffer; + let mut buffer = Buffer::with_capacity(10); + + buffer.resize(10, 0); + assert_eq!(buffer.len(), 10); + assert_eq!(buffer.capacity(), 10); + assert_eq!(buffer.buf(), &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + buffer.resize(11, 1); + assert_eq!(buffer.len(), 11); + assert_eq!(buffer.capacity(), 11); + assert_eq!(buffer.buf(), &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); + + buffer.resize(5, 2); + assert_eq!(buffer.len(), 5); + assert_eq!(buffer.capacity(), 11); + assert_eq!(buffer.buf(), &[0, 0, 0, 0, 0]); + + buffer.resize(7, 3); + assert_eq!(buffer.len(), 7); + assert_eq!(buffer.capacity(), 11); + assert_eq!(buffer.buf(), &[0, 0, 0, 0, 0, 3, 3]); + assert_eq!(buffer.usable_space(), 4); + assert_eq!(buffer.free_space(), 4); + + buffer.consume(2); + buffer.resize(7, 4); + assert_eq!(buffer.len(), 7); + assert_eq!(buffer.capacity(), 11); + assert_eq!(buffer.buf(), &[0, 0, 0, 3, 3, 4, 4]); + assert_eq!(buffer.usable_space(), 2); + assert_eq!(buffer.free_space(), 4); + + buffer.resize(11, 5); + assert_eq!(buffer.len(), 11); + assert_eq!(buffer.capacity(), 13); + assert_eq!(buffer.buf(), &[0, 0, 0, 3, 3, 4, 4, 5, 5, 5, 5]); + assert_eq!(buffer.usable_space(), 0); + assert_eq!(buffer.free_space(), 2); + + buffer.make_room(); + assert_eq!(buffer.usable_space(), 2); + assert_eq!(buffer.free_space(), 2); + + buffer.resize(13, 6); + assert_eq!(buffer.len(), 13); + assert_eq!(buffer.capacity(), 13); + assert_eq!(buffer.buf(), &[0, 0, 0, 3, 3, 4, 4, 5, 5, 5, 5, 6, 6]); + assert_eq!(buffer.usable_space(), 0); + assert_eq!(buffer.free_space(), 0); + + buffer.resize(0, 7); + assert_eq!(buffer.len(), 0); + assert_eq!(buffer.capacity(), 13); + assert_eq!(buffer.buf(), &[]); + assert_eq!(buffer.usable_space(), 13); + assert_eq!(buffer.free_space(), 13); +} diff --git a/src/lib.rs b/src/lib.rs index 6a5365a..fafce52 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1012,6 +1012,31 @@ impl Buffer { } } + /// Resizes the buffer in-place sto that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, the buffer is extended by the difference, + /// with each additional slot filled with `value`. If `new_len` is less than `len`, + /// the buffer is simply truncated. + /// + /// Note that this will reallocate even if there is enough free space at the head of + /// the buffer if `len() + usable_space() < new_len`. + /// + /// If you prefer copying data down in the buffer before attempting to reallocate + /// you may wish to call `.make_room()` first. + pub fn resize(&mut self, new_len: usize, value: u8) { + // Returns `true` if we reallocated out-of-place and thus need to re-zero. + if self.buf.resize(new_len, value) { + self.zeroed = 0; + } + } + + /// Resizes the buffer in-place sto that `len` is equal to `new_len`. + /// + /// Same as calling `.resize(new_len, 0)`. + pub fn resize_default(&mut self, new_len: usize) { + self.buf.resize(new_len, 0); + } + /// Get an immutable slice of the available bytes in this buffer. /// /// Call `.consume()` to remove bytes from the beginning of this slice. @@ -1175,6 +1200,13 @@ impl Buffer { self.buf.consume(amt); } + /// Shortens the buffer, keeping the first `len`. + /// + /// If `len` is greater then buffer's length, this has no effect. + pub fn truncate(&mut self, len: usize) { + self.buf.truncate(len); + } + /// Empty this buffer by consuming all bytes. pub fn clear(&mut self) { let buf_len = self.len();