trait Buf

Tokio trait Buf,从缓冲区读取字节。

https://docs.rs/bytes/1.0.1/bytes/trait.Buf.html

文档

介绍

从缓冲区读取字节。

缓冲区将字节存储在内存中,这样的读取操作是无懈可击的。底层存储可能是也可能不是在连续的内存中。一个Buf值是一个进入缓冲区的光标。从Buf中读出的数据会使游标位置前进。它可以被认为是一个有效的字节集合的Iterator。

最简单的Buf是 &[u8]

use bytes::Buf;

let mut buf = &b"hello world"[..];

assert_eq!(b'h', buf.get_u8());
assert_eq!(b'e', buf.get_u8());
assert_eq!(b'l', buf.get_u8());

let mut rest = [0; 8];
buf.copy_to_slice(&mut rest);

assert_eq!(&rest[..], &b"lo world"[..]);

源码

remaining()

返回当前位置和缓冲区末端之间的字节数。

这个值大于或等于 chunk() 返回的 slice 的长度。

use bytes::Buf;

let mut buf = &b"hello world"[..];

assert_eq!(buf.remaining(), 11);

buf.get_u8();

assert_eq!(buf.remaining(), 10);

实现注意: remaining的实现应该确保返回值不发生变化,除非调用 advance 或其他任何有记录的函数来改变Buf的当前位置。

方法定义为:

fn remaining(&self) -> usize;

chunk()

返回一个从当前位置开始,长度在 0 和 Buf::remaining() 之间的片断。注意,这可以返回更短的片断(这允许非连续的内部表示)。

这是一个较低级别的函数。大多数操作是由其他函数完成的。

use bytes::Buf;

let mut buf = &b"hello world"[..];

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

buf.advance(6);

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

实现说明:

这个函数不应该panic。一旦到达缓冲区的末端,即 Buf::remaining 返回0,对 chunk() 的调用应该返回一个空片段。

方法定义为:

fn chunk(&self) -> &[u8];

advance()

推进 Buf 的内部游标。

下一次对 chunk() 的调用将返回一个开始于底层缓冲区的 cnt 个字节的分片。

use bytes::Buf;

let mut buf = &b"hello world"[..];

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

buf.advance(6);

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

实现须知:

建议 advance 的实现在 cnt > self.relative() 的情况下进行 panic。如果实现没有panic,调用必须表现为 cnt == self.restaining()

一个 cnt == 0 的调用不应该panic,而应该是 no-op。

方法定义为:

fn advance(&mut self, cnt: usize);

chunks_vectored()

从自己的当前位置开始,用潜在的多个片断填充dst。

如果 Buf 是由不相干的字节片断支持的,chunk_vectored 可以一次获取多个片断。 dst是一个 IoSlice 的引用,使得该片可以直接被 writev 使用,而不需要进一步转换。dst 中所有缓冲区的长度之和将小于或等于 Buf::reserved()

dst 中的条目将被覆盖,但分片所包含的数据不会被修改。如果 chunk_vectored 没有填满dst中的每一个条目,那么dst将保证包含 ``self`中的所有剩余片断。

这是一个较低级别的函数。大多数操作是由其他函数完成的。

实现说明:

这个函数不应该panic。一旦到达缓冲区的末端,即 Buf::remaining 返回0,对 chunk_vectored 的调用必须返回0而不改变dst。

实现者还应该注意正确处理dst为零长度片断时的调用。

代码实现为:

fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
    if dst.is_empty() {
        return 0;
    }

    if self.has_remaining() {
        dst[0] = IoSlice::new(self.chunk());
        1
    } else {
        0
    }
}

remaining()

如果还有更多的字节需要消耗,则返回true。

这等同于 self.remaining() != 0

use bytes::Buf;

let mut buf = &b"a"[..];

assert!(buf.has_remaining());

buf.get_u8();

assert!(!buf.has_remaining());

代码实现:

fn has_remaining(&self) -> bool {
    self.remaining() > 0
}

copy_to_slice()

pub fn copy_to_slice(&mut self, dst: &mut [u8])

从 self 复制字节到 dst。

光标按复制的字节数前进,self 必须有足够的剩余字节来填充dst。

use bytes::Buf;

let mut buf = &b"hello world"[..];
let mut dst = [0; 5];

buf.copy_to_slice(&mut dst);
assert_eq!(&b"hello"[..], &dst);
assert_eq!(6, buf.remaining());

代码实现:

fn copy_to_slice(&mut self, dst: &mut [u8]) {
    let mut off = 0;

    assert!(self.remaining() >= dst.len());

    while off < dst.len() {
        let cnt;

        unsafe {
            let src = self.chunk();
            cnt = cmp::min(src.len(), dst.len() - off);

            ptr::copy_nonoverlapping(src.as_ptr(), dst[off..].as_mut_ptr(), cnt);

            off += cnt;
        }

        self.advance(cnt);
    }
}

get_u8()

pub fn get_u8(&mut self) -> u8

从自身获取一个无符号的8位整数。

当前位置推进 1。

代码实现:

fn get_u8(&mut self) -> u8 {
    assert!(self.remaining() >= 1);
    let ret = self.chunk()[0];
    self.advance(1);
    ret
}

get_i8()

pub fn get_i8(&mut self) -> i8

从自身获取一个有符号的8位整数。

当前位置推进 1。

copy_to_bytes()

pub fn copy_to_bytes(&mut self, len: usize) -> Bytes

消耗 self 内部的 len 个字节,并返回带有这些数据的新 Bytes 实例。

这个函数可能被底层类型优化以避免实际的拷贝。例如,Bytes 的实现会做一个浅层拷贝(ref-count增量)。

use bytes::Buf;

let bytes = (&b"hello world"[..]).copy_to_bytes(5);
assert_eq!(&bytes[..], &b"hello"[..]);

代码实现为:

fn copy_to_bytes(&mut self, len: usize) -> crate::Bytes {
    use super::BufMut;

    assert!(len <= self.remaining(), "`len` greater than remaining");

    let mut ret = crate::BytesMut::with_capacity(len);
    ret.put(self.take(len));
    ret.freeze()
}

take()

pub fn take(self, limit: usize) -> Take<Self>

创建一个适配器,它将从 self 读取最多 limit 个字节。

这个函数返回新的 Buf 实例,它将最多读取 limit 个字节。

use bytes::{Buf, BufMut};

let mut buf = b"hello world"[..].take(5);
let mut dst = vec![];

dst.put(&mut buf);
assert_eq!(dst, b"hello");

let mut buf = buf.into_inner();
dst.clear();
dst.put(&mut buf);
assert_eq!(dst, b" world");

代码实现为:

fn take(self, limit: usize) -> Take<Self>
where
    Self: Sized,
{
    take::new(self, limit)
}

chain()

pub fn chain<U: Buf>(self, next: U) -> Chain<Self, U>

创建一个适配器,将这个缓冲区与另一个缓冲区连接起来。

返回的 Buf 实例将首先消耗来自 self 的所有字节。之后的输出相当于Next的输出。

use bytes::Buf;

let mut chain = b"hello "[..].chain(&b"world"[..]);

let full = chain.copy_to_bytes(11);
assert_eq!(full.chunk(), b"hello world");