trait Buf
文档
介绍
从缓冲区读取字节。
缓冲区将字节存储在内存中,这样的读取操作是无懈可击的。底层存储可能是也可能不是在连续的内存中。一个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");