Rust 如何在tokio_core::io::Codec::decode(…)中实现零拷贝?
我的目标是实现一个Rust 如何在tokio_core::io::Codec::decode(…)中实现零拷贝?,rust,rust-tokio,Rust,Rust Tokio,我的目标是实现一个Codec,它将提供的EasyBuf抽取到消息边界,并将其解码为仅引用内容的结构,以防止不必要的复制。 查看EasyBuf的实现,目前似乎不可能实现,但可能我遗漏了一些东西 以下是我使用的代码,这样做实际上是为了: struct V>, } 结构C; C语言的impl编解码器{ 输入=R{ buf:&'a mut Vec, 结束:&'a mut usize, } 简单易用{ pub fn new()->EasyBuf{ EasyBuf::具有_容量(8*1024) } 酒吧fn
Codec
,它将提供的EasyBuf
抽取到消息边界,并将其解码为仅引用内容的结构,以防止不必要的复制。
查看EasyBuf
的实现,目前似乎不可能实现,但可能我遗漏了一些东西
以下是我使用的代码,这样做实际上是为了:
struct V>,
}
结构C;
C语言的impl编解码器{
输入=R{
buf:&'a mut Vec,
结束:&'a mut usize,
}
简单易用{
pub fn new()->EasyBuf{
EasyBuf::具有_容量(8*1024)
}
酒吧fn,容量(上限:usize)->EasyBuf{
轻松的{
buf:Arc::新建(Vec::带容量(cap)),
起点:0,
完:0,,
}
}
fn set_start(&mut self,start:usize)->&mut EasyBuf{
断言!(启动EasyBuf){
让mut other=EasyBuf{buf:self.buf.clone(),..*self};
设idx=self.start+at;
其他。设置启动(idx);
自整定端(idx);
归还他人;
}
pub fn drain_to(&mut self,at:usize)->EasyBuf{
让mut other=EasyBuf{buf:self.buf.clone(),..*self};
设idx=self.start+at;
其他。设置_端(idx);
自启动(idx);
归还他人;
}
pub fn get_mut(&mut self)->EasyBufMut{
if Arc::get_mut(&mut self.buf.)。是_some(){
让buf=Arc::get_mut(&mut self.buf).unwrap();
buf.排水管(…自启动);
self.start=0;
返回EasyBufMut{
buf:buf,
结束:&mut self.end,
};
}
设mut v=Vec::with_capacity(self.buf.capacity());
v、 从_切片(self.as_ref())扩展_;
self.start=0;
self.buf=弧::新(v);
易如反掌{
buf:Arc::get_mut(&mut self.buf).unwrap(),
结束:&mut self.end,
}
}
}
EasyBuf的impl AsRef{
fn作为参考(&self)->和[u8]{
&self.buf[self.start..self.end]
}
}
恳求{
类型目标=Vec;
fn deref(&self)->&Vec{
自我介绍
}
}
恳求{
fn deref_mut(&mut self)->&mut Vec{
自我介绍
}
}
来自EasyBuf的impl{
fn from(vec:vec)->EasyBuf{
让end=vec.len();
轻松的{
buf:Arc::新建(vec),
起点:0,
完:完,,
}
}
}
恳求{
fn下降(&mut自我){
*self.end=self.buf.len();
}
}
///通过缓冲器对帧进行编码和解码。
///
///此特性在构造“Framed”的实例时使用。它提供
///两种类型:`In`,用于解码输入帧;`Out`,用于输出帧
///它还提供了实际执行
///编码和解码,与相应的缓冲区类型一起工作。
///
///trait本身是在一个可以跟踪解码状态的类型上实现的
///或编码,这对于流式解析器特别有用
///不过,在某些情况下,这种类型只是一个单元结构(例如,`struct
///HttpCodec`)。
发布特性编解码器{
///解码帧的类型。
输入;
///要编码的帧的类型。
打字;
///尝试从提供的字节缓冲区解码帧。
///
///每当字节准备好进行解析时,“Framed”就会调用此方法。
///提供的字节缓冲区是到目前为止已读取的,并且
///'Decode'的实例可以确定整个帧是否在
///缓冲区,并准备返回。
///
///如果整个帧可用,则此实例将删除这些帧
///从提供的缓冲区返回字节,并将其作为解码
///请注意,从提供的缓冲区中删除字节并不总是
///必须复制字节,因此这应该是一个高效的操作
///大多数情况下。
///
///如果字节看起来有效,但帧尚未完全可用,则
///返回'Ok(None)'。这向'Framed'实例指示
///在再次调用此方法之前,它需要读取更多字节。
///
///最后,如果缓冲区中的字节格式不正确,则会出现错误
///返回,说明原因。这会通知'Framed',流现在已被设置
///腐败,应该终止。
fn解码(&mut self,buf:&mut EasyBuf)->io::Result;
///没有更多字节时可调用的默认方法
///可从底层I/O读取。
///
///此方法默认调用'decode',如果
///返回`Ok(None)`通常不需要实现
///除非帧协议在流末尾附近不同。
fn decode_eof(&mut self,buf:&mut EasyBuf)->io::Result{
匹配尝试!(自我解码(buf)){
一些(帧)=>正常(帧),
None=>Err(io::Error::new(io::ErrorKind::Other,“流上剩余的字节”),
}
}
///将帧编码到提供的缓冲区中。
///
///此方法将“msg”编码到“buf”提供的字节缓冲区中。
///提供的'buf'是'Framed'实例的内部缓冲区,并且
///在可能的情况下会写出来。
fn encode(&mut self,msg:self::Out,buf:&mut Vec)->io::Result;
}
思想
- 由于
中缺少生存期,我认为目前无法实现这一点-我们必须声明它是静态的,这是借阅检查器的问题Codec::in
- 它可以通过返回
本身(EasyBuf
)来实现,并在稍后的步骤中进行解码,例如在类似于中的未来链接中进行解码Codec::In=EasyBuf
- 它也可以通过将索引解析到EasyBuf中,并通过使用reference生成实际的数据类型来实现
struct V<'a> { s: &'a [u8], } struct R<'a> { b: EasyBuf, v: Option<V<'a>>, } struct C; impl Codec for C { type In = R<'static>; type Out = String; fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Self::In>> { let mut r = R { b: buf.clone(), v: None, }; r.v = Some(V { s: r.b.as_slice() }); Ok(Some(r)) } fn encode(&mut self, msg: Self::Out, buf: &mut Vec<u8>) -> io::Result<()> { Ok(()) } } fn main() { let b = EasyBuf::new(); let mut r = R { b: b, v: None }; r.v = Some(V { s: r.b.as_slice() }); } use std::fmt; use std::io; use std::ops::{Deref, DerefMut}; use std::sync::Arc; #[derive(Clone)] pub struct EasyBuf { buf: Arc<Vec<u8>>, start: usize, end: usize, } pub struct EasyBufMut<'a> { buf: &'a mut Vec<u8>, end: &'a mut usize, } impl EasyBuf { pub fn new() -> EasyBuf { EasyBuf::with_capacity(8 * 1024) } pub fn with_capacity(cap: usize) -> EasyBuf { EasyBuf { buf: Arc::new(Vec::with_capacity(cap)), start: 0, end: 0, } } fn set_start(&mut self, start: usize) -> &mut EasyBuf { assert!(start <= self.buf.as_ref().len()); assert!(start <= self.end); self.start = start; self } fn set_end(&mut self, end: usize) -> &mut EasyBuf { assert!(end <= self.buf.len()); assert!(self.start <= end); self.end = end; self } pub fn len(&self) -> usize { self.end - self.start } pub fn as_slice(&self) -> &[u8] { self.as_ref() } pub fn split_off(&mut self, at: usize) -> EasyBuf { let mut other = EasyBuf { buf: self.buf.clone(), ..*self }; let idx = self.start + at; other.set_start(idx); self.set_end(idx); return other; } pub fn drain_to(&mut self, at: usize) -> EasyBuf { let mut other = EasyBuf { buf: self.buf.clone(), ..*self }; let idx = self.start + at; other.set_end(idx); self.set_start(idx); return other; } pub fn get_mut(&mut self) -> EasyBufMut { if Arc::get_mut(&mut self.buf).is_some() { let buf = Arc::get_mut(&mut self.buf).unwrap(); buf.drain(..self.start); self.start = 0; return EasyBufMut { buf: buf, end: &mut self.end, }; } let mut v = Vec::with_capacity(self.buf.capacity()); v.extend_from_slice(self.as_ref()); self.start = 0; self.buf = Arc::new(v); EasyBufMut { buf: Arc::get_mut(&mut self.buf).unwrap(), end: &mut self.end, } } } impl AsRef<[u8]> for EasyBuf { fn as_ref(&self) -> &[u8] { &self.buf[self.start..self.end] } } impl<'a> Deref for EasyBufMut<'a> { type Target = Vec<u8>; fn deref(&self) -> &Vec<u8> { self.buf } } impl<'a> DerefMut for EasyBufMut<'a> { fn deref_mut(&mut self) -> &mut Vec<u8> { self.buf } } impl From<Vec<u8>> for EasyBuf { fn from(vec: Vec<u8>) -> EasyBuf { let end = vec.len(); EasyBuf { buf: Arc::new(vec), start: 0, end: end, } } } impl<'a> Drop for EasyBufMut<'a> { fn drop(&mut self) { *self.end = self.buf.len(); } } /// Encoding and decoding of frames via buffers. /// /// This trait is used when constructing an instance of `Framed`. It provides /// two types: `In`, for decoded input frames, and `Out`, for outgoing frames /// that need to be encoded. It also provides methods to actually perform the /// encoding and decoding, which work with corresponding buffer types. /// /// The trait itself is implemented on a type that can track state for decoding /// or encoding, which is particularly useful for streaming parsers. In many /// cases, though, this type will simply be a unit struct (e.g. `struct /// HttpCodec`). pub trait Codec { /// The type of decoded frames. type In; /// The type of frames to be encoded. type Out; /// Attempts to decode a frame from the provided buffer of bytes. /// /// This method is called by `Framed` whenever bytes are ready to be parsed. /// The provided buffer of bytes is what's been read so far, and this /// instance of `Decode` can determine whether an entire frame is in the /// buffer and is ready to be returned. /// /// If an entire frame is available, then this instance will remove those /// bytes from the buffer provided and return them as a decoded /// frame. Note that removing bytes from the provided buffer doesn't always /// necessarily copy the bytes, so this should be an efficient operation in /// most circumstances. /// /// If the bytes look valid, but a frame isn't fully available yet, then /// `Ok(None)` is returned. This indicates to the `Framed` instance that /// it needs to read some more bytes before calling this method again. /// /// Finally, if the bytes in the buffer are malformed then an error is /// returned indicating why. This informs `Framed` that the stream is now /// corrupt and should be terminated. fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Self::In>>; /// A default method available to be called when there are no more bytes /// available to be read from the underlying I/O. /// /// This method defaults to calling `decode` and returns an error if /// `Ok(None)` is returned. Typically this doesn't need to be implemented /// unless the framing protocol differs near the end of the stream. fn decode_eof(&mut self, buf: &mut EasyBuf) -> io::Result<Self::In> { match try!(self.decode(buf)) { Some(frame) => Ok(frame), None => Err(io::Error::new(io::ErrorKind::Other, "bytes remaining on stream")), } } /// Encodes a frame into the buffer provided. /// /// This method will encode `msg` into the byte buffer provided by `buf`. /// The `buf` provided is an internal buffer of the `Framed` instance and /// will be written out when possible. fn encode(&mut self, msg: Self::Out, buf: &mut Vec<u8>) -> io::Result<()>; }
pub struct PacketCodec { pub data_todo: Option<usize>, } type PacketItem = Frame<PacketHeader, BytesMut, io::Error>; impl PacketHeader { pub fn admin_decode(buf: &mut BytesMut) -> Result<Option<PacketItem>, io::Error> { let newline = buf[..].iter().position(|b| *b == b'\n'); if let Some(n) = newline { let line = buf.split_to(n); buf.split_to(1); // drop the newline itself let data_str = match str::from_utf8(&line[..]) { Ok(s) => s, Err(_) => return Err(io::Error::new(io::ErrorKind::Other, "invalid string")), }; info!("admin command data: {:?}", data_str); let command = match data_str.trim() { "version" => ADMIN_VERSION, "status" => ADMIN_STATUS, _ => ADMIN_UNKNOWN, }; return Ok(Some(Frame::Message { message: PacketHeader { magic: PacketMagic::TEXT, ptype: command, psize: 0, }, body: false, })); } Ok(None) // Wait for more data } pub fn decode(buf: &mut BytesMut) -> Result<Option<PacketItem>, io::Error> { debug!("Decoding {:?}", buf); // Peek at first 4 // Is this a req/res if buf.len() < 4 { return Ok(None); } let mut magic_buf: [u8; 4] = [0; 4]; magic_buf.clone_from_slice(&buf[0..4]); let magic = match magic_buf { REQ => PacketMagic::REQ, RES => PacketMagic::RES, // TEXT/ADMIN protocol _ => PacketMagic::TEXT, }; debug!("Magic is {:?}", magic); if magic == PacketMagic::TEXT { debug!("admin protocol detected"); return PacketHeader::admin_decode(buf); } if buf.len() < 12 { return Ok(None); } buf.split_to(4); // Now get the type let ptype = buf.split_to(4).into_buf().get_u32::<BigEndian>(); debug!("We got a {}", &PTYPES[ptype as usize].name); // Now the length let psize = buf.split_to(4).into_buf().get_u32::<BigEndian>(); debug!("Data section is {} bytes", psize); Ok(Some(Frame::Message { message: PacketHeader { magic: magic, ptype: ptype, psize: psize, }, body: true, // TODO: false for 0 psize? })) } } impl Decoder for PacketCodec { type Item = Frame<PacketHeader, BytesMut, io::Error>; type Error = io::Error; fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, io::Error> { match self.data_todo { None => { match PacketHeader::decode(buf)? { Some(Frame::Message { message, body }) => { self.data_todo = Some(message.psize as usize); Ok(Some(Frame::Message { message: message, body: body, })) } Some(_) => panic!("Expecting Frame::Message, got something else"), None => Ok(None), } } Some(0) => { self.data_todo = None; Ok(Some(Frame::Body { chunk: None })) } Some(data_todo) => { let chunk_size = min(buf.len(), data_todo); self.data_todo = Some(data_todo - chunk_size); Ok(Some(Frame::Body { chunk: Some(buf.split_to(chunk_size)) })) } } } }