aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bytes.rs32
-rw-r--r--tests/test_bytes.rs45
2 files changed, 75 insertions, 2 deletions
diff --git a/src/bytes.rs b/src/bytes.rs
index b4745a9..0404a72 100644
--- a/src/bytes.rs
+++ b/src/bytes.rs
@@ -807,8 +807,36 @@ impl From<&'static str> for Bytes {
impl From<Vec<u8>> for Bytes {
fn from(vec: Vec<u8>) -> Bytes {
- let slice = vec.into_boxed_slice();
- slice.into()
+ let mut vec = vec;
+ let ptr = vec.as_mut_ptr();
+ let len = vec.len();
+ let cap = vec.capacity();
+
+ // Avoid an extra allocation if possible.
+ if len == cap {
+ return Bytes::from(vec.into_boxed_slice());
+ }
+
+ let shared = Box::new(Shared {
+ buf: ptr,
+ cap,
+ ref_cnt: AtomicUsize::new(1),
+ });
+ mem::forget(vec);
+
+ let shared = Box::into_raw(shared);
+ // The pointer should be aligned, so this assert should
+ // always succeed.
+ debug_assert!(
+ 0 == (shared as usize & KIND_MASK),
+ "internal: Box<Shared> should have an aligned pointer",
+ );
+ Bytes {
+ ptr,
+ len,
+ data: AtomicPtr::new(shared as _),
+ vtable: &SHARED_VTABLE,
+ }
}
}
diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs
index 4ddb24d..5ec60a5 100644
--- a/tests/test_bytes.rs
+++ b/tests/test_bytes.rs
@@ -1163,3 +1163,48 @@ fn test_bytes_into_vec_promotable_even() {
assert_eq!(Vec::from(b2), vec[20..]);
assert_eq!(Vec::from(b1), vec[..20]);
}
+
+#[test]
+fn test_bytes_vec_conversion() {
+ let mut vec = Vec::with_capacity(10);
+ vec.extend(b"abcdefg");
+ let b = Bytes::from(vec);
+ let v = Vec::from(b);
+ assert_eq!(v.len(), 7);
+ assert_eq!(v.capacity(), 10);
+
+ let mut b = Bytes::from(v);
+ b.advance(1);
+ let v = Vec::from(b);
+ assert_eq!(v.len(), 6);
+ assert_eq!(v.capacity(), 10);
+ assert_eq!(v.as_slice(), b"bcdefg");
+}
+
+#[test]
+fn test_bytes_mut_conversion() {
+ let mut b1 = BytesMut::with_capacity(10);
+ b1.extend(b"abcdefg");
+ let b2 = Bytes::from(b1);
+ let v = Vec::from(b2);
+ assert_eq!(v.len(), 7);
+ assert_eq!(v.capacity(), 10);
+
+ let mut b = Bytes::from(v);
+ b.advance(1);
+ let v = Vec::from(b);
+ assert_eq!(v.len(), 6);
+ assert_eq!(v.capacity(), 10);
+ assert_eq!(v.as_slice(), b"bcdefg");
+}
+
+#[test]
+fn test_bytes_capacity_len() {
+ for cap in 0..100 {
+ for len in 0..=cap {
+ let mut v = Vec::with_capacity(cap);
+ v.resize(len, 0);
+ let _ = Bytes::from(v);
+ }
+ }
+}