Skip to content

Commit b9c8170

Browse files
committed
Address review: Add safety comments, update docs
1 parent 3fa520b commit b9c8170

1 file changed

Lines changed: 58 additions & 35 deletions

File tree

src/bytes_mut.rs

Lines changed: 58 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -827,15 +827,18 @@ impl BytesMut {
827827
}
828828
}
829829

830-
/// Attempts to reclaim the whole allocation of the `BytesMut`.
830+
/// Attempts to cheaply reclaim the whole allocation of the `BytesMut`.
831831
///
832-
/// If the `BytesMut` is empty but the underlying storage has been used before,
833-
/// it might be possible to cheaply reclaim capacity as long as there are no
834-
/// other `Bytes` or `BytesMut` handles alive.
832+
/// If no other `Bytes` or `BytesMut` handles to the underlying storage of this
833+
/// `BytesMut` are alive, it might be possible to cheaply reclaim the full capacity
834+
/// of the allocation.
835835
///
836-
/// Returns `true` if the allocation was reclaimed (or reclaiming was not
837-
/// necessary, because the underlying storage was empty); returns `false` if the
838-
/// `BytesMut` is not empty or there are other outstanding references to the
836+
/// `try_reclaim` never copies bytes internally, therefore it always returns `false`
837+
/// if the `BytesMut` is not empty.
838+
///
839+
/// Returns `true` if the allocation was reclaimed (or reclaiming was not necessary,
840+
/// because the underlying storage was already fully available); returns `false` if the
841+
/// `BytesMut` is not empty or there are other outstanding handles to the
839842
/// underlying storage.
840843
///
841844
/// # Examples
@@ -845,15 +848,22 @@ impl BytesMut {
845848
///
846849
/// let mut buf = BytesMut::with_capacity(64);
847850
/// assert_eq!(true, buf.try_reclaim());
851+
/// assert_eq!(64, buf.capacity());
848852
///
849853
/// buf.extend_from_slice(b"abcd");
850854
/// let mut split = buf.split();
855+
/// assert_eq!(60, buf.capacity());
856+
/// assert_eq!(4, split.capacity());
851857
/// assert_eq!(false, split.try_reclaim());
852858
/// assert_eq!(false, buf.try_reclaim());
859+
///
853860
/// drop(buf);
854861
/// assert_eq!(false, split.try_reclaim());
862+
///
855863
/// split.clear();
864+
/// assert_eq!(4, split.capacity());
856865
/// assert_eq!(true, split.try_reclaim());
866+
/// assert_eq!(64, split.capacity());
857867
/// ```
858868
#[must_use = "consider BytesMut::reserve if you need a specific capacity"]
859869
pub fn try_reclaim(&mut self) -> bool {
@@ -863,41 +873,54 @@ impl BytesMut {
863873

864874
let kind = self.kind();
865875
if kind == KIND_VEC {
866-
unsafe {
867-
// Short-circuit if we are already at the start of the vector.
868-
let off = self.get_vec_pos();
869-
if off == 0 {
870-
return true;
871-
}
872-
// Otherwise, update info to point at the front of the vector
873-
// again and reclaim capacity
874-
let base_ptr = self.ptr.as_ptr().sub(off);
875-
self.ptr = vptr(base_ptr);
876-
self.set_vec_pos(0);
877-
self.cap += off;
876+
// Safety: self is of KIND_VEC, so calling get_vec_pos() is safe.
877+
let off = unsafe { self.get_vec_pos() };
878+
879+
// Short-circuit if we are already at the start of the vector.
880+
if off == 0 {
878881
return true;
879882
}
883+
// Otherwise, update info to point at the front of the vector
884+
// again and reclaim capacity
885+
//
886+
// Safety: Offset `off` means self.ptr was moved `off` bytes from the base
887+
// pointer of the allocation. Going back to the base pointer stays within
888+
// that same allocation.
889+
let base_ptr = unsafe { self.ptr.as_ptr().sub(off) };
890+
self.ptr = vptr(base_ptr);
891+
892+
// Safety: Resetting the offset to 0 is safe as we reset the storage
893+
// pointer to the base pointer of the allocation above
894+
unsafe { self.set_vec_pos(0) }
895+
self.cap += off;
896+
897+
return true;
880898
}
899+
900+
debug_assert_eq!(kind, KIND_ARC);
881901
let shared: *mut Shared = self.data;
882902

883-
unsafe {
884-
// If there are other references to the underlying storage, we cannot reclaim
885-
if !(*shared).is_unique() {
886-
return false;
887-
}
888-
let v = &mut (*shared).vec;
889-
let cap = v.capacity();
890-
if cap == 0 {
891-
// Short-circuit as an empty vector is trivially reclaimed already
892-
return true;
893-
}
903+
// If there are other references to the underlying storage, we cannot reclaim
904+
//
905+
// Safety: self is of type KIND_ARC, so the Shared ptr is valid
906+
if unsafe { !(*shared).is_unique() } {
907+
return false;
908+
}
894909

895-
// Update info to point at start of allocation and reclaim capacity
896-
let ptr = v.as_mut_ptr();
897-
self.ptr = vptr(ptr);
898-
self.cap = cap;
899-
true
910+
// Safety: self is of type KIND_ARC and there are no other handles alive, so we
911+
// can get a mut reference to the underlying storage
912+
let v = unsafe { &mut (*shared).vec };
913+
let cap = v.capacity();
914+
if cap == 0 {
915+
// Short-circuit as an empty vector is trivially reclaimed already
916+
return true;
900917
}
918+
919+
// Update info to point at start of allocation and reclaim capacity
920+
let ptr = v.as_mut_ptr();
921+
self.ptr = vptr(ptr);
922+
self.cap = cap;
923+
true
901924
}
902925

903926
// private

0 commit comments

Comments
 (0)