我的目标是实现一个Codec
将提供的内容排到EasyBuf
消息边界并将其解码为仅引用内容的结构以防止不必要的复制。研究 的实现EasyBuf
,目前似乎不可能,但也许我遗漏了一些东西。
这是我正在使用的代码,并且这样做实际上是tokio-cassandra所需要的:
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<()>;
}
想法
- 由于缺少生命周期,我认为目前无法做到这一点
Codec::In
- 我们必须声明它'static
,这就是借用检查器的问题。 - 它可以通过返回自身
EasyBuf
(Codec::In = EasyBuf
- 它也可以通过将索引解析到 EasyBuf 中来实现,并通过延迟生成具有引用的实际数据类型来实现。例如,字符串只是 a
(usize, *const u8)
,稍后&str
在用户请求时变为 a 。