rlp stream
This commit is contained in:
parent
6006f7cc38
commit
798b8b0fb8
103
src/rlp.rs
103
src/rlp.rs
@ -191,8 +191,86 @@ impl <'a> Iterator for RlpIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// container that should be used to encoding the rlp
|
||||||
|
pub struct RlpStream {
|
||||||
|
len: usize,
|
||||||
|
max_len: usize,
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
last_err: Option<EncoderError>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RlpStream {
|
||||||
|
/// create new container of size `max_len`
|
||||||
|
pub fn new(max_len: usize) -> RlpStream {
|
||||||
|
RlpStream {
|
||||||
|
len: 0,
|
||||||
|
max_len: max_len,
|
||||||
|
bytes: vec![],
|
||||||
|
last_err: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// apends value to the end of stream, chainable
|
||||||
|
pub fn append<'a, E>(&'a mut self, object: &E) -> &'a mut RlpStream where E: Encodable {
|
||||||
|
// if there was an error, stop appending
|
||||||
|
if !self.last_err.is_none() {
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode given value and add it at the end of the stream
|
||||||
|
match encode(object) {
|
||||||
|
Err(e) => {
|
||||||
|
self.last_err = Some(e);
|
||||||
|
return self;
|
||||||
|
},
|
||||||
|
Ok(ref mut v) => {
|
||||||
|
self.bytes.append(v);
|
||||||
|
self.len += 1;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// if array is finished, prepend the length
|
||||||
|
if self.is_finished() {
|
||||||
|
self.prepend_the_length();
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow chaining calls
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return try if stream is ready
|
||||||
|
pub fn is_finished(&self) -> bool {
|
||||||
|
self.len == self.max_len
|
||||||
|
}
|
||||||
|
|
||||||
|
/// streams out encoded bytes
|
||||||
|
pub fn out(self) -> Result<Vec<u8>, EncoderError> {
|
||||||
|
match self.last_err {
|
||||||
|
None if self.is_finished() => Ok(self.bytes),
|
||||||
|
Some(e) => Err(e),
|
||||||
|
_ => Err(EncoderError::StreamIsUnfinished)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// prepend the length of the bytes to the beginning of the vector
|
||||||
|
fn prepend_the_length(&mut self) -> () {
|
||||||
|
let mut v = match self.bytes.len() {
|
||||||
|
len @ 0...55 => vec![0xc0u8 + len as u8],
|
||||||
|
len => {
|
||||||
|
let mut res = vec![0x7fu8 + len.to_bytes_len() as u8];
|
||||||
|
let mut b = len.to_bytes();
|
||||||
|
res.append(&mut b);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
v.append(&mut self.bytes);
|
||||||
|
self.bytes = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// shortcut function to encode a `T: Encodable` into a Rlp `Vec<u8>`
|
/// shortcut function to encode a `T: Encodable` into a Rlp `Vec<u8>`
|
||||||
pub fn encode<E>(object: &E) -> Result<Vec<u8>, EncoderError> where E: Encodable {
|
fn encode<E>(object: &E) -> Result<Vec<u8>, EncoderError> where E: Encodable {
|
||||||
let mut ret: Vec<u8> = vec![];
|
let mut ret: Vec<u8> = vec![];
|
||||||
{
|
{
|
||||||
let mut encoder = BasicEncoder::new(&mut ret);
|
let mut encoder = BasicEncoder::new(&mut ret);
|
||||||
@ -203,7 +281,8 @@ pub fn encode<E>(object: &E) -> Result<Vec<u8>, EncoderError> where E: Encodable
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum EncoderError {
|
pub enum EncoderError {
|
||||||
IoError(IoError)
|
IoError(IoError),
|
||||||
|
StreamIsUnfinished
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdError for EncoderError {
|
impl StdError for EncoderError {
|
||||||
@ -257,16 +336,16 @@ impl <'a, T> Encodable for &'a [T] where T: Encodable + 'a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn item_info(&self) -> ItemInfo {
|
fn item_info(&self) -> ItemInfo {
|
||||||
let prefix_len = match self.len() {
|
|
||||||
0...55 => 1,
|
|
||||||
len => len.to_bytes_len()
|
|
||||||
};
|
|
||||||
|
|
||||||
let value_len = self.iter().fold(0, |acc, ref enc| {
|
let value_len = self.iter().fold(0, |acc, ref enc| {
|
||||||
let item = enc.item_info();
|
let item = enc.item_info();
|
||||||
acc + item.prefix_len + item.value_len
|
acc + item.prefix_len + item.value_len
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let prefix_len = match value_len {
|
||||||
|
0...55 => 1,
|
||||||
|
len => len.to_bytes_len()
|
||||||
|
};
|
||||||
|
|
||||||
ItemInfo::new(prefix_len, value_len)
|
ItemInfo::new(prefix_len, value_len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -342,7 +421,7 @@ impl <W> Encoder for BasicEncoder<W> where W: Write {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use rlp;
|
use rlp;
|
||||||
use rlp::Rlp;
|
use rlp::{Rlp, RlpStream};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rlp_at() {
|
fn rlp_at() {
|
||||||
@ -511,5 +590,13 @@ mod tests {
|
|||||||
];
|
];
|
||||||
run_encode_tests(tests);
|
run_encode_tests(tests);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rlp_stream() {
|
||||||
|
let mut stream = RlpStream::new(2);
|
||||||
|
stream.append(&"cat").append(&"dog");
|
||||||
|
let out = stream.out().unwrap();
|
||||||
|
assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user