RLP encoder refactoring
This commit is contained in:
parent
e61d1f810e
commit
40314614f7
@ -23,6 +23,7 @@ elastic-array = "0.4"
|
|||||||
heapsize = "0.2"
|
heapsize = "0.2"
|
||||||
itertools = "0.4"
|
itertools = "0.4"
|
||||||
crossbeam = "0.2"
|
crossbeam = "0.2"
|
||||||
|
smallvec = "0.1"
|
||||||
slab = { git = "https://github.com/arkpar/slab.git" }
|
slab = { git = "https://github.com/arkpar/slab.git" }
|
||||||
sha3 = { path = "sha3" }
|
sha3 = { path = "sha3" }
|
||||||
clippy = "*" # Always newest, since we use nightly
|
clippy = "*" # Always newest, since we use nightly
|
||||||
|
@ -42,8 +42,37 @@ use std::error::Error as StdError;
|
|||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use uint::{Uint, U128, U256};
|
use uint::{Uint, U128, U256};
|
||||||
use hash::FixedHash;
|
use hash::FixedHash;
|
||||||
|
use elastic_array::*;
|
||||||
|
|
||||||
/// TODO [Gav Wood] Please document me
|
/// Vector like object
|
||||||
|
pub trait VecLike<T> {
|
||||||
|
/// Add an element to the collection
|
||||||
|
fn push(&mut self, value: T);
|
||||||
|
|
||||||
|
/// Add a slice to the collection
|
||||||
|
fn extend(&mut self, slice: &[T]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
macro_rules! impl_veclike_for_elastic_array {
|
||||||
|
($from: ident) => {
|
||||||
|
impl<T> VecLike<T> for $from<T> where T: Copy {
|
||||||
|
fn push(&mut self, value: T) {
|
||||||
|
$from::<T>::push(self, value)
|
||||||
|
}
|
||||||
|
fn extend(&mut self, slice: &[T]) {
|
||||||
|
$from::<T>::append_slice(self, slice)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_veclike_for_elastic_array!(ElasticArray16);
|
||||||
|
impl_veclike_for_elastic_array!(ElasticArray32);
|
||||||
|
impl_veclike_for_elastic_array!(ElasticArray1024);
|
||||||
|
|
||||||
|
/// Slie pretty print helper
|
||||||
pub struct PrettySlice<'a> (&'a [u8]);
|
pub struct PrettySlice<'a> (&'a [u8]);
|
||||||
|
|
||||||
impl<'a> fmt::Debug for PrettySlice<'a> {
|
impl<'a> fmt::Debug for PrettySlice<'a> {
|
||||||
@ -170,49 +199,47 @@ fn bytes_convertable() {
|
|||||||
///
|
///
|
||||||
/// TODO: optimise some conversations
|
/// TODO: optimise some conversations
|
||||||
pub trait ToBytes {
|
pub trait ToBytes {
|
||||||
/// TODO [Gav Wood] Please document me
|
/// Serialize self to byte array
|
||||||
fn to_bytes(&self) -> Vec<u8>;
|
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V);
|
||||||
/// TODO [Gav Wood] Please document me
|
/// Get length of serialized data in bytes
|
||||||
fn to_bytes_len(&self) -> usize { self.to_bytes().len() }
|
fn to_bytes_len(&self) -> usize;
|
||||||
/// TODO [debris] Please document me
|
|
||||||
fn first_byte(&self) -> Option<u8> { self.to_bytes().first().map(|&x| { x })}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a> ToBytes for &'a str {
|
impl <'a> ToBytes for &'a str {
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
|
||||||
From::from(*self)
|
out.extend(self.as_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_bytes_len(&self) -> usize { self.len() }
|
fn to_bytes_len(&self) -> usize {
|
||||||
|
self.as_bytes().len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToBytes for String {
|
impl ToBytes for String {
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
|
||||||
let s: &str = self.as_ref();
|
out.extend(self.as_bytes());
|
||||||
From::from(s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_bytes_len(&self) -> usize { self.len() }
|
fn to_bytes_len(&self) -> usize {
|
||||||
|
self.len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToBytes for u64 {
|
impl ToBytes for u64 {
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
|
||||||
let mut res= vec![];
|
|
||||||
let count = self.to_bytes_len();
|
let count = self.to_bytes_len();
|
||||||
res.reserve(count);
|
|
||||||
for i in 0..count {
|
for i in 0..count {
|
||||||
let j = count - 1 - i;
|
let j = count - 1 - i;
|
||||||
res.push((*self >> (j * 8)) as u8);
|
out.push((*self >> (j * 8)) as u8);
|
||||||
}
|
}
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_bytes_len(&self) -> usize { 8 - self.leading_zeros() as usize / 8 }
|
fn to_bytes_len(&self) -> usize { 8 - self.leading_zeros() as usize / 8 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToBytes for bool {
|
impl ToBytes for bool {
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
|
||||||
vec![ if *self { 1u8 } else { 0u8 } ]
|
out.push(if *self { 1u8 } else { 0u8 })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_bytes_len(&self) -> usize { 1 }
|
fn to_bytes_len(&self) -> usize { 1 }
|
||||||
@ -221,28 +248,29 @@ impl ToBytes for bool {
|
|||||||
macro_rules! impl_map_to_bytes {
|
macro_rules! impl_map_to_bytes {
|
||||||
($from: ident, $to: ty) => {
|
($from: ident, $to: ty) => {
|
||||||
impl ToBytes for $from {
|
impl ToBytes for $from {
|
||||||
fn to_bytes(&self) -> Vec<u8> { (*self as $to).to_bytes() }
|
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
|
||||||
|
(*self as $to).to_bytes(out)
|
||||||
|
}
|
||||||
|
|
||||||
fn to_bytes_len(&self) -> usize { (*self as $to).to_bytes_len() }
|
fn to_bytes_len(&self) -> usize { (*self as $to).to_bytes_len() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_map_to_bytes!(usize, u64);
|
impl_map_to_bytes!(usize, u64);
|
||||||
|
impl_map_to_bytes!(u8, u64);
|
||||||
impl_map_to_bytes!(u16, u64);
|
impl_map_to_bytes!(u16, u64);
|
||||||
impl_map_to_bytes!(u32, u64);
|
impl_map_to_bytes!(u32, u64);
|
||||||
|
|
||||||
macro_rules! impl_uint_to_bytes {
|
macro_rules! impl_uint_to_bytes {
|
||||||
($name: ident) => {
|
($name: ident) => {
|
||||||
impl ToBytes for $name {
|
impl ToBytes for $name {
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
|
||||||
let mut res= vec![];
|
|
||||||
let count = self.to_bytes_len();
|
let count = self.to_bytes_len();
|
||||||
res.reserve(count);
|
|
||||||
for i in 0..count {
|
for i in 0..count {
|
||||||
let j = count - 1 - i;
|
let j = count - 1 - i;
|
||||||
res.push(self.byte(j));
|
out.push(self.byte(j));
|
||||||
}
|
}
|
||||||
res
|
|
||||||
}
|
}
|
||||||
fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 }
|
fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 }
|
||||||
}
|
}
|
||||||
@ -253,18 +281,10 @@ impl_uint_to_bytes!(U256);
|
|||||||
impl_uint_to_bytes!(U128);
|
impl_uint_to_bytes!(U128);
|
||||||
|
|
||||||
impl <T>ToBytes for T where T: FixedHash {
|
impl <T>ToBytes for T where T: FixedHash {
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
|
||||||
let mut res: Vec<u8> = vec![];
|
out.extend(self.bytes());
|
||||||
res.reserve(T::size());
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
use std::ptr;
|
|
||||||
ptr::copy(self.bytes().as_ptr(), res.as_mut_ptr(), T::size());
|
|
||||||
res.set_len(T::size());
|
|
||||||
}
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
fn to_bytes_len(&self) -> usize { self.bytes().len() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error returned when FromBytes conversation goes wrong
|
/// Error returned when FromBytes conversation goes wrong
|
||||||
|
@ -86,8 +86,8 @@ impl JournalDB {
|
|||||||
|
|
||||||
let mut r = RlpStream::new_list(3);
|
let mut r = RlpStream::new_list(3);
|
||||||
r.append(id);
|
r.append(id);
|
||||||
r.append(&self.inserts);
|
r.append_list(&self.inserts);
|
||||||
r.append(&self.removes);
|
r.append_list(&self.removes);
|
||||||
try!(self.backing.put(&last, r.as_raw()));
|
try!(self.backing.put(&last, r.as_raw()));
|
||||||
self.inserts.clear();
|
self.inserts.clear();
|
||||||
self.removes.clear();
|
self.removes.clear();
|
||||||
|
@ -55,6 +55,7 @@ extern crate secp256k1;
|
|||||||
extern crate arrayvec;
|
extern crate arrayvec;
|
||||||
extern crate elastic_array;
|
extern crate elastic_array;
|
||||||
extern crate crossbeam;
|
extern crate crossbeam;
|
||||||
|
extern crate smallvec;
|
||||||
|
|
||||||
/// TODO [Gav Wood] Please document me
|
/// TODO [Gav Wood] Please document me
|
||||||
pub mod standard;
|
pub mod standard;
|
||||||
|
@ -124,11 +124,10 @@ pub struct CapabilityInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Encodable for CapabilityInfo {
|
impl Encodable for CapabilityInfo {
|
||||||
fn encode<E>(&self, encoder: &mut E) -> () where E: Encoder {
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
encoder.emit_list(|e| {
|
s.begin_list(2);
|
||||||
self.protocol.encode(e);
|
s.append(&self.protocol);
|
||||||
(self.version as u32).encode(e);
|
s.append(&self.version);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,10 +199,10 @@ impl Session {
|
|||||||
fn write_hello(&mut self, host: &HostInfo) -> Result<(), UtilError> {
|
fn write_hello(&mut self, host: &HostInfo) -> Result<(), UtilError> {
|
||||||
let mut rlp = RlpStream::new();
|
let mut rlp = RlpStream::new();
|
||||||
rlp.append_raw(&[PACKET_HELLO as u8], 0);
|
rlp.append_raw(&[PACKET_HELLO as u8], 0);
|
||||||
rlp.append_list(5)
|
rlp.begin_list(5)
|
||||||
.append(&host.protocol_version)
|
.append(&host.protocol_version)
|
||||||
.append(&host.client_version)
|
.append(&host.client_version)
|
||||||
.append(&host.capabilities)
|
.append_list(&host.capabilities)
|
||||||
.append(&host.listen_port)
|
.append(&host.listen_port)
|
||||||
.append(host.id());
|
.append(host.id());
|
||||||
self.connection.send_packet(&rlp.out())
|
self.connection.send_packet(&rlp.out())
|
||||||
@ -267,7 +267,7 @@ impl Session {
|
|||||||
fn disconnect(&mut self, reason: DisconnectReason) -> NetworkError {
|
fn disconnect(&mut self, reason: DisconnectReason) -> NetworkError {
|
||||||
let mut rlp = RlpStream::new();
|
let mut rlp = RlpStream::new();
|
||||||
rlp.append(&(PACKET_DISCONNECT as u32));
|
rlp.append(&(PACKET_DISCONNECT as u32));
|
||||||
rlp.append_list(1);
|
rlp.begin_list(1);
|
||||||
rlp.append(&(reason.clone() as u32));
|
rlp.append(&(reason.clone() as u32));
|
||||||
self.connection.send_packet(&rlp.out()).ok();
|
self.connection.send_packet(&rlp.out()).ok();
|
||||||
NetworkError::Disconnect(reason)
|
NetworkError::Disconnect(reason)
|
||||||
@ -276,7 +276,7 @@ impl Session {
|
|||||||
fn prepare(packet_id: u8) -> Result<RlpStream, UtilError> {
|
fn prepare(packet_id: u8) -> Result<RlpStream, UtilError> {
|
||||||
let mut rlp = RlpStream::new();
|
let mut rlp = RlpStream::new();
|
||||||
rlp.append(&(packet_id as u32));
|
rlp.append(&(packet_id as u32));
|
||||||
rlp.append_list(0);
|
rlp.begin_list(0);
|
||||||
Ok(rlp)
|
Ok(rlp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ fn test_net_service() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_net_connect() {
|
fn test_net_connect() {
|
||||||
|
::env_logger::init().ok();
|
||||||
let key1 = KeyPair::create().unwrap();
|
let key1 = KeyPair::create().unwrap();
|
||||||
let mut config1 = NetworkConfiguration::new_with_port(30344);
|
let mut config1 = NetworkConfiguration::new_with_port(30344);
|
||||||
config1.use_secret = Some(key1.secret().clone());
|
config1.use_secret = Some(key1.secret().clone());
|
||||||
|
@ -143,7 +143,6 @@ impl OverlayDB {
|
|||||||
self.backing.delete(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?");
|
self.backing.delete(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?");
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
//! * You want to get view onto rlp-slice.
|
//! * You want to get view onto rlp-slice.
|
||||||
//! * You don't want to decode whole rlp at once.
|
//! * You don't want to decode whole rlp at once.
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
/// TODO [Gav Wood] Please document me
|
/// TODO [Gav Wood] Please document me
|
||||||
pub mod rlptraits;
|
pub mod rlptraits;
|
||||||
/// TODO [Gav Wood] Please document me
|
/// TODO [Gav Wood] Please document me
|
||||||
@ -48,7 +49,8 @@ pub use self::rlperrors::DecoderError;
|
|||||||
pub use self::rlptraits::{Decoder, Decodable, View, Stream, Encodable, Encoder};
|
pub use self::rlptraits::{Decoder, Decodable, View, Stream, Encodable, Encoder};
|
||||||
pub use self::untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype};
|
pub use self::untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype};
|
||||||
pub use self::rlpin::{Rlp, RlpIterator};
|
pub use self::rlpin::{Rlp, RlpIterator};
|
||||||
pub use self::rlpstream::{RlpStream,RlpStandard};
|
pub use self::rlpstream::{RlpStream};
|
||||||
|
pub use elastic_array::ElasticArray1024;
|
||||||
use super::hash::H256;
|
use super::hash::H256;
|
||||||
|
|
||||||
/// TODO [arkpar] Please document me
|
/// TODO [arkpar] Please document me
|
||||||
@ -84,13 +86,31 @@ pub fn decode<T>(bytes: &[u8]) -> T where T: Decodable {
|
|||||||
/// use util::rlp::*;
|
/// use util::rlp::*;
|
||||||
///
|
///
|
||||||
/// fn main () {
|
/// fn main () {
|
||||||
|
/// let animal = "cat";
|
||||||
|
/// let out = encode(&animal);
|
||||||
|
/// assert_eq!(out, vec![0x83, b'c', b'a', b't']);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn encode<E>(object: &E) -> ElasticArray1024<u8> where E: Encodable {
|
||||||
|
let mut stream = RlpStream::new();
|
||||||
|
stream.append(object);
|
||||||
|
stream.drain()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shortcut function to encode a list to rlp.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::rlp::*;
|
||||||
|
///
|
||||||
|
/// fn main () {
|
||||||
/// let animals = vec!["cat", "dog"];
|
/// let animals = vec!["cat", "dog"];
|
||||||
/// let out = encode(&animals);
|
/// let out = encode_list(&animals);
|
||||||
/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
|
/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn encode<E>(object: &E) -> Vec<u8> where E: Encodable {
|
pub fn encode_list<I, E>(list: &I) -> ElasticArray1024<u8> where I: Deref<Target = [E]>, E: Encodable {
|
||||||
let mut stream = RlpStream::new();
|
let mut stream = RlpStream::new();
|
||||||
stream.append(object);
|
stream.append_list(list);
|
||||||
stream.out()
|
stream.drain()
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
use std::ops::Deref;
|
||||||
use elastic_array::*;
|
use elastic_array::*;
|
||||||
use bytes::{Bytes, ToBytes};
|
use bytes::{ToBytes, VecLike};
|
||||||
use rlp::{Stream, Encoder, Encodable};
|
use rlp::{Stream, Encoder, Encodable};
|
||||||
use hash::H256;
|
use rlp::rlptraits::ByteEncodable;
|
||||||
use sha3::*;
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
struct ListInfo {
|
struct ListInfo {
|
||||||
@ -37,22 +37,18 @@ impl Stream for RlpStream {
|
|||||||
|
|
||||||
fn new_list(len: usize) -> Self {
|
fn new_list(len: usize) -> Self {
|
||||||
let mut stream = RlpStream::new();
|
let mut stream = RlpStream::new();
|
||||||
stream.append_list(len);
|
stream.begin_list(len);
|
||||||
stream
|
stream
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append<E>(&mut self, object: &E) -> &mut RlpStream where E: Encodable {
|
fn append<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: Encodable {
|
||||||
// encode given value and add it at the end of the stream
|
value.rlp_append(self);
|
||||||
object.encode(&mut self.encoder);
|
|
||||||
|
|
||||||
// if list is finished, prepend the length
|
// if list is finished, prepend the length
|
||||||
self.note_appended(1);
|
self.note_appended(1);
|
||||||
|
|
||||||
// return chainable self
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_list(&mut self, len: usize) -> &mut RlpStream {
|
fn begin_list(&mut self, len: usize) -> &mut RlpStream {
|
||||||
match len {
|
match len {
|
||||||
0 => {
|
0 => {
|
||||||
// we may finish, if the appended list len is equal 0
|
// we may finish, if the appended list len is equal 0
|
||||||
@ -69,6 +65,15 @@ impl Stream for RlpStream {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn append_list<I, E>(&mut self, list: &I) -> &mut Self where I: Deref<Target = [E]>, E: Encodable {
|
||||||
|
let items = list.deref();
|
||||||
|
self.begin_list(items.len());
|
||||||
|
for el in items.iter() {
|
||||||
|
self.append(el);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn append_empty_data(&mut self) -> &mut RlpStream {
|
fn append_empty_data(&mut self) -> &mut RlpStream {
|
||||||
// self push raw item
|
// self push raw item
|
||||||
self.encoder.bytes.push(0x80);
|
self.encoder.bytes.push(0x80);
|
||||||
@ -117,6 +122,12 @@ impl Stream for RlpStream {
|
|||||||
|
|
||||||
impl RlpStream {
|
impl RlpStream {
|
||||||
|
|
||||||
|
/// Appends primitive value to the end of stream
|
||||||
|
fn append_value<E>(&mut self, object: &E) where E: ByteEncodable {
|
||||||
|
// encode given value and add it at the end of the stream
|
||||||
|
self.encoder.emit_value(object);
|
||||||
|
}
|
||||||
|
|
||||||
/// Try to finish lists
|
/// Try to finish lists
|
||||||
fn note_appended(&mut self, inserted_items: usize) -> () {
|
fn note_appended(&mut self, inserted_items: usize) -> () {
|
||||||
if self.unfinished_lists.len() == 0 {
|
if self.unfinished_lists.len() == 0 {
|
||||||
@ -164,12 +175,12 @@ impl BasicEncoder {
|
|||||||
/// inserts list prefix at given position
|
/// inserts list prefix at given position
|
||||||
/// TODO: optimise it further?
|
/// TODO: optimise it further?
|
||||||
fn insert_list_len_at_pos(&mut self, len: usize, pos: usize) -> () {
|
fn insert_list_len_at_pos(&mut self, len: usize, pos: usize) -> () {
|
||||||
let mut res = vec![];
|
let mut res = ElasticArray16::new();
|
||||||
match len {
|
match len {
|
||||||
0...55 => res.push(0xc0u8 + len as u8),
|
0...55 => res.push(0xc0u8 + len as u8),
|
||||||
_ => {
|
_ => {
|
||||||
res.push(0xf7u8 + len.to_bytes_len() as u8);
|
res.push(0xf7u8 + len.to_bytes_len() as u8);
|
||||||
res.extend(len.to_bytes());
|
ToBytes::to_bytes(&len, &mut res);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -183,22 +194,30 @@ impl BasicEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Encoder for BasicEncoder {
|
impl Encoder for BasicEncoder {
|
||||||
fn emit_value(&mut self, bytes: &[u8]) -> () {
|
fn emit_value<E: ByteEncodable>(&mut self, value: &E) {
|
||||||
match bytes.len() {
|
match value.bytes_len() {
|
||||||
// just 0
|
// just 0
|
||||||
0 => self.bytes.push(0x80u8),
|
0 => self.bytes.push(0x80u8),
|
||||||
// byte is its own encoding
|
// byte is its own encoding if < 0x80
|
||||||
1 if bytes[0] < 0x80 => self.bytes.append_slice(bytes),
|
1 => {
|
||||||
|
value.to_bytes(&mut self.bytes);
|
||||||
|
let len = self.bytes.len();
|
||||||
|
let last_byte = self.bytes[len - 1];
|
||||||
|
if last_byte >= 0x80 {
|
||||||
|
self.bytes.push(last_byte);
|
||||||
|
self.bytes[len - 1] = 0x81;
|
||||||
|
}
|
||||||
|
}
|
||||||
// (prefix + length), followed by the string
|
// (prefix + length), followed by the string
|
||||||
len @ 1 ... 55 => {
|
len @ 2 ... 55 => {
|
||||||
self.bytes.push(0x80u8 + len as u8);
|
self.bytes.push(0x80u8 + len as u8);
|
||||||
self.bytes.append_slice(bytes);
|
value.to_bytes(&mut self.bytes);
|
||||||
}
|
}
|
||||||
// (prefix + length of length), followed by the length, followd by the string
|
// (prefix + length of length), followed by the length, followd by the string
|
||||||
len => {
|
len => {
|
||||||
self.bytes.push(0xb7 + len.to_bytes_len() as u8);
|
self.bytes.push(0xb7 + len.to_bytes_len() as u8);
|
||||||
self.bytes.append_slice(&len.to_bytes());
|
ToBytes::to_bytes(&len, &mut self.bytes);
|
||||||
self.bytes.append_slice(bytes);
|
value.to_bytes(&mut self.bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -206,86 +225,41 @@ impl Encoder for BasicEncoder {
|
|||||||
fn emit_raw(&mut self, bytes: &[u8]) -> () {
|
fn emit_raw(&mut self, bytes: &[u8]) -> () {
|
||||||
self.bytes.append_slice(bytes);
|
self.bytes.append_slice(bytes);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn emit_list<F>(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> () {
|
|
||||||
// get len before inserting a list
|
|
||||||
let before_len = self.bytes.len();
|
|
||||||
|
|
||||||
// insert all list elements
|
impl<T> ByteEncodable for T where T: ToBytes {
|
||||||
f(self);
|
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
|
||||||
|
ToBytes::to_bytes(self, out)
|
||||||
|
}
|
||||||
|
|
||||||
// get len after inserting a list
|
fn bytes_len(&self) -> usize {
|
||||||
let after_len = self.bytes.len();
|
ToBytes::to_bytes_len(self)
|
||||||
|
|
||||||
// diff is list len
|
|
||||||
let list_len = after_len - before_len;
|
|
||||||
self.insert_list_len_at_pos(list_len, before_len);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO [Gav Wood] Please document me
|
impl<'a> ByteEncodable for &'a[u8] {
|
||||||
pub trait RlpStandard {
|
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
|
||||||
/// TODO [Gav Wood] Please document me
|
out.extend(self)
|
||||||
fn rlp_append(&self, s: &mut RlpStream);
|
|
||||||
|
|
||||||
/// TODO [Gav Wood] Please document me
|
|
||||||
fn rlp_bytes(&self) -> Bytes {
|
|
||||||
let mut s = RlpStream::new();
|
|
||||||
self.rlp_append(&mut s);
|
|
||||||
s.out()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO [Gav Wood] Please document me
|
fn bytes_len(&self) -> usize {
|
||||||
fn rlp_sha3(&self) -> H256 { self.rlp_bytes().sha3() }
|
self.len()
|
||||||
}
|
|
||||||
|
|
||||||
// @debris TODO: implement Encoder for RlpStandard.
|
|
||||||
|
|
||||||
impl<T> Encodable for T where T: ToBytes {
|
|
||||||
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
|
|
||||||
encoder.emit_value(&self.to_bytes())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> Encodable for &'a [T] where T: Encodable + 'a {
|
impl ByteEncodable for Vec<u8> {
|
||||||
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
|
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
|
||||||
encoder.emit_list(|e| {
|
out.extend(self.deref())
|
||||||
// insert all list elements
|
}
|
||||||
for el in self.iter() {
|
|
||||||
el.encode(e);
|
fn bytes_len(&self) -> usize {
|
||||||
}
|
self.len()
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Encodable for Vec<T> where T: Encodable {
|
impl<T> Encodable for T where T: ByteEncodable {
|
||||||
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
let r: &[T] = self.as_ref();
|
s.append_value(self)
|
||||||
r.encode(encoder)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// lets treat bytes differently than other lists
|
|
||||||
/// they are a single value
|
|
||||||
impl<'a> Encodable for &'a [u8] {
|
|
||||||
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
|
|
||||||
encoder.emit_value(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// lets treat bytes differently than other lists
|
|
||||||
/// they are a single value
|
|
||||||
impl Encodable for Vec<u8> {
|
|
||||||
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
|
|
||||||
encoder.emit_value(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Encodable for Option<T> where T: Encodable {
|
|
||||||
fn encode<E>(&self, encoder: &mut E) where E: Encoder {
|
|
||||||
match *self {
|
|
||||||
Some(ref x) => x.encode(encoder),
|
|
||||||
None => encoder.emit_value(&[])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
|
use std::ops::Deref;
|
||||||
|
use bytes::VecLike;
|
||||||
use rlp::{DecoderError, UntrustedRlp};
|
use rlp::{DecoderError, UntrustedRlp};
|
||||||
|
use rlpstream::RlpStream;
|
||||||
|
use elastic_array::ElasticArray1024;
|
||||||
|
use hash::H256;
|
||||||
|
use sha3::*;
|
||||||
|
|
||||||
/// TODO [debris] Please document me
|
/// TODO [debris] Please document me
|
||||||
pub trait Decoder: Sized {
|
pub trait Decoder: Sized {
|
||||||
@ -204,17 +210,33 @@ pub trait View<'a, 'view>: Sized {
|
|||||||
/// TODO [debris] Please document me
|
/// TODO [debris] Please document me
|
||||||
pub trait Encoder {
|
pub trait Encoder {
|
||||||
/// TODO [debris] Please document me
|
/// TODO [debris] Please document me
|
||||||
fn emit_value(&mut self, bytes: &[u8]) -> ();
|
fn emit_value<E: ByteEncodable>(&mut self, value: &E);
|
||||||
/// TODO [Gav Wood] Please document me
|
|
||||||
fn emit_list<F>(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> ();
|
|
||||||
/// TODO [debris] Please document me
|
/// TODO [debris] Please document me
|
||||||
fn emit_raw(&mut self, bytes: &[u8]) -> ();
|
fn emit_raw(&mut self, bytes: &[u8]) -> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO [debris] Please document me
|
/// Primitive data type encodable to RLP
|
||||||
|
pub trait ByteEncodable {
|
||||||
|
/// Serialize this object to given byte container
|
||||||
|
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V);
|
||||||
|
/// Get size of serialised data in bytes
|
||||||
|
fn bytes_len(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Structure encodable to RLP
|
||||||
pub trait Encodable {
|
pub trait Encodable {
|
||||||
/// TODO [debris] Please document me
|
/// Append a value to the stream
|
||||||
fn encode<E>(&self, encoder: &mut E) -> () where E: Encoder;
|
fn rlp_append(&self, s: &mut RlpStream);
|
||||||
|
|
||||||
|
/// Get rlp-encoded bytes for this instance
|
||||||
|
fn rlp_bytes(&self) -> ElasticArray1024<u8> {
|
||||||
|
let mut s = RlpStream::new();
|
||||||
|
self.rlp_append(&mut s);
|
||||||
|
s.drain()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the hash or RLP encoded representation
|
||||||
|
fn rlp_sha3(&self) -> H256 { self.rlp_bytes().deref().sha3() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO [debris] Please document me
|
/// TODO [debris] Please document me
|
||||||
@ -239,7 +261,7 @@ pub trait Stream: Sized {
|
|||||||
/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
|
/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
fn append<'a, E>(&'a mut self, object: &E) -> &'a mut Self where E: Encodable;
|
fn append<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: Encodable;
|
||||||
|
|
||||||
/// Declare appending the list of given size, chainable.
|
/// Declare appending the list of given size, chainable.
|
||||||
///
|
///
|
||||||
@ -249,13 +271,28 @@ pub trait Stream: Sized {
|
|||||||
///
|
///
|
||||||
/// fn main () {
|
/// fn main () {
|
||||||
/// let mut stream = RlpStream::new_list(2);
|
/// let mut stream = RlpStream::new_list(2);
|
||||||
/// stream.append_list(2).append(&"cat").append(&"dog");
|
/// stream.begin_list(2).append(&"cat").append(&"dog");
|
||||||
/// stream.append(&"");
|
/// stream.append(&"");
|
||||||
/// let out = stream.out();
|
/// let out = stream.out();
|
||||||
/// assert_eq!(out, vec![0xca, 0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g', 0x80]);
|
/// assert_eq!(out, vec![0xca, 0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g', 0x80]);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
fn append_list(&mut self, len: usize) -> &mut Self;
|
fn begin_list(&mut self, len: usize) -> &mut Self;
|
||||||
|
|
||||||
|
/// Append the given list, chainable.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::rlp::*;
|
||||||
|
///
|
||||||
|
/// fn main () {
|
||||||
|
/// let mut stream = RlpStream::new_list(2);
|
||||||
|
/// stream.begin_list([&"cat", &"dog"]);
|
||||||
|
/// let out = stream.out();
|
||||||
|
/// assert_eq!(out, vec![0xca, 0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g', 0x80]);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn append_list<I, E>(&mut self, list: &I) -> &mut Self where I: Deref<Target = [E]>, E: Encodable;
|
||||||
|
|
||||||
/// Apends null to the end of stream, chainable.
|
/// Apends null to the end of stream, chainable.
|
||||||
///
|
///
|
||||||
|
@ -77,13 +77,23 @@ fn rlp_iter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ETestPair<T>(T, Vec<u8>) where T: rlp::Encodable;
|
struct ETestPair<T>(T, Vec<u8>) where T: rlp::Encodable;
|
||||||
|
struct ETestVecPair<T>(Vec<T>, Vec<u8>) where T: rlp::Encodable;
|
||||||
|
|
||||||
fn run_encode_tests<T>(tests: Vec<ETestPair<T>>)
|
fn run_encode_tests<T>(tests: Vec<ETestPair<T>>)
|
||||||
where T: rlp::Encodable
|
where T: rlp::Encodable
|
||||||
{
|
{
|
||||||
for t in &tests {
|
for t in &tests {
|
||||||
let res = rlp::encode(&t.0);
|
let res = rlp::encode(&t.0);
|
||||||
assert_eq!(res, &t.1[..]);
|
assert_eq!(&res[..], &t.1[..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_encode_list_tests<T>(tests: Vec<ETestVecPair<T>>)
|
||||||
|
where T: rlp::Encodable
|
||||||
|
{
|
||||||
|
for t in &tests {
|
||||||
|
let res = rlp::encode_list(&t.0);
|
||||||
|
assert_eq!(&res[..], &t.1[..]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,25 +188,19 @@ fn encode_vector_u8() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn encode_vector_u64() {
|
fn encode_vector_u64() {
|
||||||
let tests = vec![
|
let tests = vec![
|
||||||
ETestPair(vec![], vec![0xc0]),
|
ETestVecPair(vec![], vec![0xc0]),
|
||||||
ETestPair(vec![15u64], vec![0xc1, 0x0f]),
|
ETestVecPair(vec![15u64], vec![0xc1, 0x0f]),
|
||||||
ETestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]),
|
ETestVecPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]),
|
||||||
ETestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]),
|
ETestVecPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]),
|
||||||
];
|
];
|
||||||
run_encode_tests(tests);
|
run_encode_list_tests(tests);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encode_vector_str() {
|
fn encode_vector_str() {
|
||||||
let tests = vec![ETestPair(vec!["cat", "dog"],
|
let tests = vec![ETestVecPair(vec!["cat", "dog"],
|
||||||
vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])];
|
vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])];
|
||||||
run_encode_tests(tests);
|
run_encode_list_tests(tests);
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn encode_vector_of_vectors_str() {
|
|
||||||
let tests = vec![ETestPair(vec![vec!["cat"]], vec![0xc5, 0xc4, 0x83, b'c', b'a', b't'])];
|
|
||||||
run_encode_tests(tests);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DTestPair<T>(T, Vec<u8>) where T: rlp::Decodable + fmt::Debug + cmp::Eq;
|
struct DTestPair<T>(T, Vec<u8>) where T: rlp::Decodable + fmt::Debug + cmp::Eq;
|
||||||
@ -333,7 +337,7 @@ fn test_rlp_json() {
|
|||||||
for operation in input.into_iter() {
|
for operation in input.into_iter() {
|
||||||
match operation {
|
match operation {
|
||||||
rlptest::Operation::Append(ref v) => stream.append(v),
|
rlptest::Operation::Append(ref v) => stream.append(v),
|
||||||
rlptest::Operation::AppendList(len) => stream.append_list(len),
|
rlptest::Operation::AppendList(len) => stream.begin_list(len),
|
||||||
rlptest::Operation::AppendRaw(ref raw, len) => stream.append_raw(raw, len),
|
rlptest::Operation::AppendRaw(ref raw, len) => stream.append_raw(raw, len),
|
||||||
rlptest::Operation::AppendEmpty => stream.append_empty_data()
|
rlptest::Operation::AppendEmpty => stream.append_empty_data()
|
||||||
};
|
};
|
||||||
@ -346,7 +350,7 @@ fn test_rlp_json() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_decoding_array() {
|
fn test_decoding_array() {
|
||||||
let v = vec![5u16, 2u16];
|
let v = vec![5u16, 2u16];
|
||||||
let res = rlp::encode(&v);
|
let res = rlp::encode_list(&v);
|
||||||
let arr: [u16; 2] = rlp::decode(&res);
|
let arr: [u16; 2] = rlp::decode(&res);
|
||||||
assert_eq!(arr[0], 5);
|
assert_eq!(arr[0], 5);
|
||||||
assert_eq!(arr[1], 2);
|
assert_eq!(arr[1], 2);
|
||||||
|
@ -89,17 +89,17 @@ impl<'a> Node<'a> {
|
|||||||
let mut stream = RlpStream::new();
|
let mut stream = RlpStream::new();
|
||||||
match *self {
|
match *self {
|
||||||
Node::Leaf(ref slice, ref value) => {
|
Node::Leaf(ref slice, ref value) => {
|
||||||
stream.append_list(2);
|
stream.begin_list(2);
|
||||||
stream.append(&slice.encoded(true));
|
stream.append(&slice.encoded(true));
|
||||||
stream.append(value);
|
stream.append(value);
|
||||||
},
|
},
|
||||||
Node::Extension(ref slice, ref raw_rlp) => {
|
Node::Extension(ref slice, ref raw_rlp) => {
|
||||||
stream.append_list(2);
|
stream.begin_list(2);
|
||||||
stream.append(&slice.encoded(false));
|
stream.append(&slice.encoded(false));
|
||||||
stream.append_raw(raw_rlp, 1);
|
stream.append_raw(raw_rlp, 1);
|
||||||
},
|
},
|
||||||
Node::Branch(ref nodes, ref value) => {
|
Node::Branch(ref nodes, ref value) => {
|
||||||
stream.append_list(17);
|
stream.begin_list(17);
|
||||||
for i in 0..16 {
|
for i in 0..16 {
|
||||||
stream.append_raw(nodes[i], 1);
|
stream.append_raw(nodes[i], 1);
|
||||||
}
|
}
|
||||||
|
@ -684,11 +684,11 @@ mod tests {
|
|||||||
|
|
||||||
fn random_value_indexed(j: usize) -> Bytes {
|
fn random_value_indexed(j: usize) -> Bytes {
|
||||||
match random::<usize>() % 2 {
|
match random::<usize>() % 2 {
|
||||||
0 => encode(&j),
|
0 => encode(&j).to_vec(),
|
||||||
_ => {
|
_ => {
|
||||||
let mut h = H256::new();
|
let mut h = H256::new();
|
||||||
h.as_slice_mut()[31] = j as u8;
|
h.as_slice_mut()[31] = j as u8;
|
||||||
encode(&h)
|
encode(&h).to_vec()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1035,7 +1035,7 @@ mod tests {
|
|||||||
let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_";
|
let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_";
|
||||||
for j in 0..4u32 {
|
for j in 0..4u32 {
|
||||||
let key = random_key(alphabet, 5, 1);
|
let key = random_key(alphabet, 5, 1);
|
||||||
x.push((key, encode(&j)));
|
x.push((key, encode(&j).to_vec()));
|
||||||
}
|
}
|
||||||
let real = trie_root(x.clone());
|
let real = trie_root(x.clone());
|
||||||
let mut memdb = MemoryDB::new();
|
let mut memdb = MemoryDB::new();
|
||||||
|
@ -30,7 +30,7 @@ pub fn ordered_trie_root(input: Vec<Vec<u8>>) -> H256 {
|
|||||||
// optimize it later
|
// optimize it later
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.fold(BTreeMap::new(), | mut acc, (i, vec) | { acc.insert(rlp::encode(&i), vec); acc })
|
.fold(BTreeMap::new(), | mut acc, (i, vec) | { acc.insert(rlp::encode(&i).to_vec(), vec); acc })
|
||||||
// then move them to a vector
|
// then move them to a vector
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(k, v)| (as_nibbles(&k), v) )
|
.map(|(k, v)| (as_nibbles(&k), v) )
|
||||||
@ -189,7 +189,7 @@ fn hash256rlp(input: &[(Vec<u8>, Vec<u8>)], pre_len: usize, stream: &mut RlpStre
|
|||||||
// if the slice contains just one item, append the suffix of the key
|
// if the slice contains just one item, append the suffix of the key
|
||||||
// and then append value
|
// and then append value
|
||||||
if inlen == 1 {
|
if inlen == 1 {
|
||||||
stream.append_list(2);
|
stream.begin_list(2);
|
||||||
stream.append(&hex_prefix_encode(&key[pre_len..], true));
|
stream.append(&hex_prefix_encode(&key[pre_len..], true));
|
||||||
stream.append(&value);
|
stream.append(&value);
|
||||||
return;
|
return;
|
||||||
@ -208,7 +208,7 @@ fn hash256rlp(input: &[(Vec<u8>, Vec<u8>)], pre_len: usize, stream: &mut RlpStre
|
|||||||
// new part of the key to the stream
|
// new part of the key to the stream
|
||||||
// then recursively append suffixes of all items who had this key
|
// then recursively append suffixes of all items who had this key
|
||||||
if shared_prefix > pre_len {
|
if shared_prefix > pre_len {
|
||||||
stream.append_list(2);
|
stream.begin_list(2);
|
||||||
stream.append(&hex_prefix_encode(&key[pre_len..shared_prefix], false));
|
stream.append(&hex_prefix_encode(&key[pre_len..shared_prefix], false));
|
||||||
hash256aux(input, shared_prefix, stream);
|
hash256aux(input, shared_prefix, stream);
|
||||||
return;
|
return;
|
||||||
@ -216,7 +216,7 @@ fn hash256rlp(input: &[(Vec<u8>, Vec<u8>)], pre_len: usize, stream: &mut RlpStre
|
|||||||
|
|
||||||
// an item for every possible nibble/suffix
|
// an item for every possible nibble/suffix
|
||||||
// + 1 for data
|
// + 1 for data
|
||||||
stream.append_list(17);
|
stream.begin_list(17);
|
||||||
|
|
||||||
// if first key len is equal to prefix_len, move to next element
|
// if first key len is equal to prefix_len, move to next element
|
||||||
let mut begin = match pre_len == key.len() {
|
let mut begin = match pre_len == key.len() {
|
||||||
|
Loading…
Reference in New Issue
Block a user