Skip to content

Commit 247b0d9

Browse files
committed
Add BytesMut::try_reserve() #484
1 parent d7c1d65 commit 247b0d9

File tree

1 file changed

+86
-15
lines changed

1 file changed

+86
-15
lines changed

src/bytes_mut.rs

Lines changed: 86 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use core::{cmp, fmt, hash, isize, slice, usize};
77
use alloc::{
88
borrow::{Borrow, BorrowMut},
99
boxed::Box,
10+
collections::TryReserveError,
1011
string::String,
1112
vec,
1213
vec::Vec,
@@ -588,22 +589,87 @@ impl BytesMut {
588589
/// Panics if the new capacity overflows `usize`.
589590
#[inline]
590591
pub fn reserve(&mut self, additional: usize) {
592+
match self.try_reserve(additional) {
593+
Err(err) => panic!("fail to reserve: {}", err),
594+
Ok(_) => {}
595+
}
596+
}
597+
598+
/// Tries to reserves capacity for at least `additional` more bytes to be inserted
599+
/// into the given `BytesMut`.
600+
///
601+
/// More than `additional` bytes may be reserved in order to avoid frequent
602+
/// reallocations. A call to `try_reserve` may result in an allocation.
603+
///
604+
/// Before allocating new buffer space, the function will attempt to reclaim
605+
/// space in the existing buffer. If the current handle references a small
606+
/// view in the original buffer and all other handles have been dropped,
607+
/// and the requested capacity is less than or equal to the existing
608+
/// buffer's capacity, then the current view will be copied to the front of
609+
/// the buffer and the handle will take ownership of the full buffer.
610+
///
611+
/// # Errors
612+
///
613+
/// If the capacity overflows, or the allocator reports a failure, then an error is returned.
614+
///
615+
/// # Examples
616+
///
617+
/// In the following example, a new buffer is allocated.
618+
///
619+
/// ```
620+
/// use bytes::BytesMut;
621+
///
622+
/// let mut buf = BytesMut::from(&b"hello"[..]);
623+
/// let res = buf.try_reserve(64);
624+
/// assert!(res.is_ok());
625+
/// assert!(buf.capacity() >= 69);
626+
/// ```
627+
///
628+
/// In the following example, the existing buffer is reclaimed.
629+
///
630+
/// ```
631+
/// use bytes::{BytesMut, BufMut};
632+
///
633+
/// let mut buf = BytesMut::with_capacity(128);
634+
/// buf.put(&[0; 64][..]);
635+
///
636+
/// let ptr = buf.as_ptr();
637+
/// let other = buf.split();
638+
///
639+
/// assert!(buf.is_empty());
640+
/// assert_eq!(buf.capacity(), 64);
641+
///
642+
/// drop(other);
643+
/// let res = buf.try_reserve(128);
644+
///
645+
/// assert!(res.is_ok());
646+
/// assert_eq!(buf.capacity(), 128);
647+
/// assert_eq!(buf.as_ptr(), ptr);
648+
/// ```
649+
#[inline]
650+
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
591651
let len = self.len();
592652
let rem = self.capacity() - len;
593653

594654
if additional <= rem {
595655
// The handle can already store at least `additional` more bytes, so
596656
// there is no further work needed to be done.
597-
return;
657+
return Ok(());
598658
}
599659

600-
// will always succeed
601-
let _ = self.reserve_inner(additional, true);
660+
self.reserve_inner(additional, true).map(
661+
// will always succeed
662+
|_| (),
663+
)
602664
}
603665

604666
// In separate function to allow the short-circuits in `reserve` and `try_reclaim` to
605667
// be inline-able. Significantly helps performance. Returns false if it did not succeed.
606-
fn reserve_inner(&mut self, additional: usize, allocate: bool) -> bool {
668+
fn reserve_inner(
669+
&mut self,
670+
additional: usize,
671+
allocate: bool,
672+
) -> Result<bool, TryReserveError> {
607673
let len = self.len();
608674
let kind = self.kind();
609675

@@ -649,21 +715,21 @@ impl BytesMut {
649715
self.cap += off;
650716
} else {
651717
if !allocate {
652-
return false;
718+
return Ok(false);
653719
}
654720
// Not enough space, or reusing might be too much overhead:
655721
// allocate more space!
656722
let mut v =
657723
ManuallyDrop::new(rebuild_vec(self.ptr.as_ptr(), self.len, self.cap, off));
658-
v.reserve(additional);
724+
v.try_reserve(additional)?;
659725

660726
// Update the info
661727
self.ptr = vptr(v.as_mut_ptr().add(off));
662728
self.cap = v.capacity() - off;
663729
debug_assert_eq!(self.len, v.len() - off);
664730
}
665731

666-
return true;
732+
return Ok(true);
667733
}
668734
}
669735

@@ -676,7 +742,7 @@ impl BytesMut {
676742
// Compute the new capacity
677743
let mut new_cap = match len.checked_add(additional) {
678744
Some(new_cap) => new_cap,
679-
None if !allocate => return false,
745+
None if !allocate => return Ok(false),
680746
None => panic!("overflow"),
681747
};
682748

@@ -710,7 +776,7 @@ impl BytesMut {
710776
self.cap = v.capacity();
711777
} else {
712778
if !allocate {
713-
return false;
779+
return Ok(false);
714780
}
715781
// calculate offset
716782
let off = (self.ptr.as_ptr() as usize) - (v.as_ptr() as usize);
@@ -743,18 +809,18 @@ impl BytesMut {
743809
// care about in the unused capacity before calling `reserve`.
744810
debug_assert!(off + len <= v.capacity());
745811
v.set_len(off + len);
746-
v.reserve(new_cap - v.len());
812+
v.try_reserve(new_cap - v.len())?;
747813

748814
// Update the info
749815
self.ptr = vptr(v.as_mut_ptr().add(off));
750816
self.cap = v.capacity() - off;
751817
}
752818

753-
return true;
819+
return Ok(true);
754820
}
755821
}
756822
if !allocate {
757-
return false;
823+
return Ok(false);
758824
}
759825

760826
let original_capacity_repr = unsafe { (*shared).original_capacity_repr };
@@ -763,7 +829,9 @@ impl BytesMut {
763829
new_cap = cmp::max(new_cap, original_capacity);
764830

765831
// Create a new vector to store the data
766-
let mut v = ManuallyDrop::new(Vec::with_capacity(new_cap));
832+
let mut v = Vec::new();
833+
v.try_reserve(new_cap)?;
834+
let mut v = ManuallyDrop::new(v);
767835

768836
// Copy the bytes
769837
v.extend_from_slice(self.as_ref());
@@ -778,7 +846,7 @@ impl BytesMut {
778846
self.ptr = vptr(v.as_mut_ptr());
779847
self.cap = v.capacity();
780848
debug_assert_eq!(self.len, v.len());
781-
return true;
849+
Ok(true)
782850
}
783851

784852
/// Attempts to cheaply reclaim already allocated capacity for at least `additional` more
@@ -838,7 +906,10 @@ impl BytesMut {
838906
return true;
839907
}
840908

841-
self.reserve_inner(additional, false)
909+
match self.reserve_inner(additional, false) {
910+
Err(err) => panic!("fail to reserve: {}", err),
911+
Ok(r) => r,
912+
}
842913
}
843914

844915
/// Appends given bytes to this `BytesMut`.

0 commit comments

Comments
 (0)