BytesMul 结构体

Tokio BytesMul 结构体,对连续的内存片段的唯一引用

https://docs.rs/bytes/1.0.1/bytes/struct.BytesMut.html

文档

介绍

对连续的内存片段的唯一引用。

BytesMut 代表了对一个潜在的共享内存区域的唯一视图。鉴于唯一性的保证,BytesMut句柄的拥有者能够改变内存。

BytesMut 可以被认为是包含一个 Buf:Arc<Vec<u8>>,一个Buf偏移量,一个分片长度,以及一个保证,即同一 Buf 的其他 BytesMut 不会与它的分片重叠。这个保证意味着不需要写锁。

增长: BytesMut 的 BufMut 实现将在必要时隐式地增长其缓冲区。然而,在一系列插入之前明确地预留所需的空间会更有效率。

use bytes::{BytesMut, BufMut};

let mut buf = BytesMut::with_capacity(64);

buf.put_u8(b'h');
buf.put_u8(b'e');
buf.put(&b"llo"[..]);

assert_eq!(&buf[..], b"hello");

// Freeze the buffer so that it can be shared
let a = buf.freeze();

// This does not allocate, instead `b` points to the same memory.
let b = a.clone();

assert_eq!(&a[..], b"hello");
assert_eq!(&b[..], b"hello");

源码

结构体定义

pub struct BytesMut {
    ptr: NonNull<u8>,
    len: usize,
    cap: usize,
    data: *mut Shared,
}

构造函数

with_capacity()

创建一个具有指定容量的新的BytesMut。

返回的BytesMut将能够容纳至少容量的字节而不需要重新分配。

值得注意的是,这个函数没有指定返回的BytesMut的长度,而只是指定了容量。

use bytes::{BytesMut, BufMut};

let mut bytes = BytesMut::with_capacity(64);

// `bytes` contains no data, even though there is capacity
assert_eq!(bytes.len(), 0);

bytes.put(&b"hello world"[..]);

assert_eq!(&bytes[..], b"hello world");

代码实现:

pub fn with_capacity(capacity: usize) -> BytesMut {
    BytesMut::from_vec(Vec::with_capacity(capacity))
}

pub(crate) fn from_vec(mut vec: Vec<u8>) -> BytesMut {
  let ptr = vptr(vec.as_mut_ptr());
  let len = vec.len();
  let cap = vec.capacity();
  mem::forget(vec);

  let original_capacity_repr = original_capacity_to_repr(cap);
  let data = (original_capacity_repr << ORIGINAL_CAPACITY_OFFSET) | KIND_VEC;

  BytesMut {
    ptr,
    len,
    cap,
    data: data as *mut _,
  }
}

new()

创建一个新的具有默认容量的BytesMut。

结果对象的长度为0,容量未指定。该函数不进行分配。

use bytes::{BytesMut, BufMut};

let mut bytes = BytesMut::new();

assert_eq!(0, bytes.len());

bytes.reserve(2);
bytes.put_slice(b"xy");

assert_eq!(&b"xy"[..], &bytes[..]);

代码实现:

pub fn new() -> BytesMut {
    // 直接 capacity = 0
    BytesMut::with_capacity(0)
}

freeze()

将自己转换为一个不可变的 Bytes。

这个转换是零成本的,用来表示由句柄引用的片断将不再被改变。一旦转换完成,句柄可以被克隆并在线程间共享。

use bytes::{BytesMut, BufMut};
use std::thread;

let mut b = BytesMut::with_capacity(64);
b.put(&b"hello world"[..]);
let b1 = b.freeze();
let b2 = b1.clone();

let th = thread::spawn(move || {
    assert_eq!(&b1[..], b"hello world");
});

assert_eq!(&b2[..], b"hello world");
th.join().unwrap();

split()

split_off()

在给定的索引处将字节分成两个。

之后 self包含元素 [0, at),而返回的 BytesMut 包含元素 [at, capacity)

这是一个O(1)操作,只是增加了引用计数并设置了一些索引。

use bytes::BytesMut;

let mut a = BytesMut::from(&b"hello world"[..]);
let mut b = a.split_off(5);

a[0] = b'j';
b[0] = b'!';

assert_eq!(&a[..], b"jello");
assert_eq!(&b[..], b"!world");

代码实现:

pub fn split_off(&mut self, at: usize) -> BytesMut {
    assert!(
        at <= self.capacity(),
        "split_off out of bounds: {:?} <= {:?}",
        at,
        self.capacity(),
    );
    unsafe {
        let mut other = self.shallow_clone();
        other.set_start(at);
        self.set_end(at);
        other
    }
}

split()

移除当前视图中的字节,在一个新的 BytesMut 句柄中返回。

之后,self 将是空的,但会保留操作前的任何额外容量。这与 self.split_to(self.len()) 是相同的。

这是一个O(1)操作,只是增加了引用计数并设置了一些索引。

use bytes::{BytesMut, BufMut};

let mut buf = BytesMut::with_capacity(1024);
buf.put(&b"hello world"[..]);

let other = buf.split();

assert!(buf.is_empty());
assert_eq!(1013, buf.capacity());

assert_eq!(other, b"hello world"[..]);

代码实现:

pub fn split(&mut self) -> BytesMut {
    let len = self.len();
    self.split_to(len)
}

split_to()

在给定的索引处将缓冲区一分为二。

之后self包含元素 [at, len),而返回的 BytesMut 包含元素 [0, at)

这是一个O(1)操作,只是增加了引用计数和设置了一些索引。

use bytes::BytesMut;

let mut a = BytesMut::from(&b"hello world"[..]);
let mut b = a.split_to(5);

a[0] = b'!';
b[0] = b'j';

assert_eq!(&a[..], b"!world");
assert_eq!(&b[..], b"jello");

代码实现:

pub fn split_to(&mut self, at: usize) -> BytesMut {
    assert!(
        at <= self.len(),
        "split_to out of bounds: {:?} <= {:?}",
        at,
        self.len(),
    );

    unsafe {
        let mut other = self.shallow_clone();
        other.set_end(at);
        self.set_start(at);
        other
    }
}

truncate()

缩短缓冲区的长度,保留第一个 len 字节,放弃其余的字节。

如果 len 大于缓冲区的当前长度,则没有影响。

split_off 方法可以模拟 Truncate,但是这导致多余的字节被返回而不是丢弃。

use bytes::BytesMut;

let mut buf = BytesMut::from(&b"hello world"[..]);
buf.truncate(5);
assert_eq!(buf, b"hello"[..]);

代码实现:

pub fn truncate(&mut self, len: usize) {
    if len <= self.len() {
        unsafe {
            self.set_len(len);
        }
    }
}

pub unsafe fn set_len(&mut self, len: usize) {
  debug_assert!(len <= self.cap, "set_len out of bounds");
  self.len = len;
}