diff --git a/boolean-bitfield/Cargo.toml b/boolean-bitfield/Cargo.toml index 6e790ea23..feacb844a 100644 --- a/boolean-bitfield/Cargo.toml +++ b/boolean-bitfield/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" authors = ["Paul Hauner "] [dependencies] +ssz = { path = "../ssz" } diff --git a/boolean-bitfield/src/lib.rs b/boolean-bitfield/src/lib.rs index da789c476..6c75e2e5e 100644 --- a/boolean-bitfield/src/lib.rs +++ b/boolean-bitfield/src/lib.rs @@ -15,59 +15,71 @@ pub struct BooleanBitfield{ } impl BooleanBitfield { + /// Create a new bitfield with a length of zero. pub fn new() -> Self { Self { len: 0, vec: vec![] } } - + + /// Create a new bitfield of a certain capacity pub fn with_capacity(capacity: usize) -> Self { Self { len: 0, - vec: Vec::with_capacity(capacity) + vec: Vec::with_capacity(capacity / 8 + 1) } } - // Output the bitfield as a big-endian vec of u8. - pub fn to_be_vec(&self) -> Vec { - let mut o = self.vec.clone(); - o.reverse(); - o - } - + /// Read the value of a bit. + /// + /// Will return `true` if the bit has been set to `true` + /// without then being set to `False`. pub fn get_bit(&self, i: &usize) -> bool { - self.get_bit_on_byte(*i % 8, *i / 8) - } + let bit = |i: &usize| *i % 8; + let byte = |i: &usize| *i / 8; - fn get_bit_on_byte(&self, bit: usize, byte: usize) -> bool { - assert!(bit < 8); - if byte >= self.vec.len() { + if byte(i) >= self.vec.len() { false } else { - self.vec[byte] & (1 << (bit as u8)) != 0 + self.vec[byte(i)] & (1 << (bit(i) as u8)) != 0 } } - pub fn set_bit(&mut self, bit: &usize, to: &bool) { - self.len = max(self.len, *bit + 1); - self.set_bit_on_byte(*bit % 8, *bit / 8, to); - } + /// Set the value of a bit. + /// + /// If this bit is larger than the length of the underlying byte + /// array it will be extended. + pub fn set_bit(&mut self, i: &usize, to: &bool) { + let bit = |i: &usize| *i % 8; + let byte = |i: &usize| *i / 8; - fn set_bit_on_byte(&mut self, bit: usize, byte: usize, val: &bool) { - assert!(bit < 8); - if byte >= self.vec.len() { - self.vec.resize(byte + 1, 0); + self.len = max(self.len, i + 1); + + if byte(i) >= self.vec.len() { + self.vec.resize(byte(i) + 1, 0); } - match val { - true => self.vec[byte] = self.vec[byte] | (1 << (bit as u8)), - false => self.vec[byte] = self.vec[byte] & !(1 << (bit as u8)) + match to { + true => { + self.vec[byte(i)] = + self.vec[byte(i)] | (1 << (bit(i) as u8)) + } + false => { + self.vec[byte(i)] = + self.vec[byte(i)] & !(1 << (bit(i) as u8)) + } } } + /// Return the "length" of this bitfield. Length is defined as + /// the highest bit that has been set. + /// + /// Note: this is distinct from the length of the underlying + /// vector. pub fn len(&self) -> usize { self.len } - // Return the total number of bits set to true. + /// Iterate through the underlying vector and count the number of + /// true bits. pub fn num_true_bits(&self) -> u64 { let mut count: u64 = 0; for byte in &self.vec { @@ -79,6 +91,13 @@ impl BooleanBitfield { } count } + + /// Clone and return the underlying byte array (`Vec`). + pub fn to_vec(&self) -> Vec { + let mut o = self.vec.clone(); + o.reverse(); + o + } } impl PartialEq for BooleanBitfield { @@ -101,49 +120,49 @@ impl Clone for BooleanBitfield { #[cfg(test)] mod tests { use super::*; - use super::rlp; #[test] fn test_bitfield_set() { let mut b = BooleanBitfield::new(); b.set_bit(&0, &false); - assert_eq!(b.to_be_vec(), [0]); - + assert_eq!(b.to_vec(), [0]); + b = BooleanBitfield::new(); b.set_bit(&7, &true); - assert_eq!(b.to_be_vec(), [128]); + assert_eq!(b.to_vec(), [128]); b.set_bit(&7, &false); - assert_eq!(b.to_be_vec(), [0]); + assert_eq!(b.to_vec(), [0]); assert_eq!(b.len(), 8); - + b = BooleanBitfield::new(); b.set_bit(&7, &true); b.set_bit(&0, &true); - assert_eq!(b.to_be_vec(), [129]); + assert_eq!(b.to_vec(), [129]); b.set_bit(&7, &false); - assert_eq!(b.to_be_vec(), [1]); + assert_eq!(b.to_vec(), [1]); assert_eq!(b.len(), 8); - + b = BooleanBitfield::new(); b.set_bit(&8, &true); - assert_eq!(b.to_be_vec(), [1, 0]); - b.set_bit(&8, &false); - assert_eq!(b.to_be_vec(), [0, 0]); + assert_eq!(b.to_vec(), [1, 0]); assert_eq!(b.len(), 9); - + b.set_bit(&8, &false); + assert_eq!(b.to_vec(), [0, 0]); + assert_eq!(b.len(), 9); + b = BooleanBitfield::new(); b.set_bit(&15, &true); - assert_eq!(b.to_be_vec(), [128, 0]); + assert_eq!(b.to_vec(), [128, 0]); b.set_bit(&15, &false); - assert_eq!(b.to_be_vec(), [0, 0]); + assert_eq!(b.to_vec(), [0, 0]); assert_eq!(b.len(), 16); - + b = BooleanBitfield::new(); b.set_bit(&8, &true); b.set_bit(&15, &true); - assert_eq!(b.to_be_vec(), [129, 0]); + assert_eq!(b.to_vec(), [129, 0]); b.set_bit(&15, &false); - assert_eq!(b.to_be_vec(), [1, 0]); + assert_eq!(b.to_vec(), [1, 0]); assert_eq!(b.len(), 16); } @@ -156,9 +175,9 @@ mod tests { b.set_bit(&i, &true); assert_eq!(b.get_bit(&i), true); b.set_bit(&i, &true); - } + } } - + #[test] fn test_bitfield_num_true_bits() { let mut b = BooleanBitfield::new(); diff --git a/ssz/src/lib.rs b/ssz/src/lib.rs index 9b392a875..f1ab50ad2 100644 --- a/ssz/src/lib.rs +++ b/ssz/src/lib.rs @@ -1,8 +1,8 @@ /* - * This is a WIP of implementing an alternative + * This is a WIP of implementing an alternative * serialization strategy. It attempts to follow Vitalik's - * "ssz" format here: - * https://github.com/ethereum/research/tree/master/py_ssz + * "simpleserialize" format here: + * https://github.com/ethereum/beacon_chain/blob/master/beacon_chain/utils/simpleserialize.py * * This implementation is not final and would almost certainly * have issues. @@ -24,12 +24,14 @@ pub struct SszStream { } impl SszStream { + /// Create a new, empty steam for writing ssz values. pub fn new() -> Self { SszStream { buffer: Vec::new() } } + /// Append some ssz encodable value to the stream. pub fn append(&mut self, value: &E) -> &mut Self where E: Encodable { @@ -37,30 +39,34 @@ impl SszStream { self } - fn append_encoded_vec(&mut self, v: &mut Vec) { - self.buffer.append(&mut encode_length(v.len(), LENGTH_BYTES)); - self.buffer.append(v) ; + pub fn extend_buffer(&mut self, vec: &mut Vec) { + self.buffer.append(&mut encode_length(vec.len(), LENGTH_BYTES)); + self.buffer.append(vec); } - - fn append_encoded_array(&mut self, a: &mut [u8]) { + + /// Append some vector (list) of encoded values to the stream. + pub fn append_vec(&mut self, vec: &mut Vec) + where E: Encodable + { + self.buffer.append(&mut encode_length(vec.len(), LENGTH_BYTES)); + for v in vec { + v.ssz_append(self); + } + } + + /// Append some array (list) of encoded values to the stream. + pub fn append_encoded_array(&mut self, a: &mut [u8]) { let len = a.len(); self.buffer.append(&mut encode_length(len, LENGTH_BYTES)); self.buffer.extend_from_slice(&a[0..len]); } + /// Consume the stream and return the underlying bytes. pub fn drain(self) -> Vec { self.buffer } } -pub fn encode(value: &E) -> Vec - where E: Encodable -{ - let mut stream = SszStream::new(); - stream.append(value); - stream.drain() -} - fn encode_length(len: usize, length_bytes: usize) -> Vec { assert!(length_bytes > 0); // For sanity assert!((len as usize) < 2usize.pow(length_bytes as u32 * 8)); @@ -75,12 +81,25 @@ fn encode_length(len: usize, length_bytes: usize) -> Vec { /* * Implementations for various types */ +impl Encodable for u8 { + fn ssz_append(&self, s: &mut SszStream) { + s.buffer.append(&mut vec![*self]); + } +} + +impl Encodable for u16 { + fn ssz_append(&self, s: &mut SszStream) { + let mut buf = BytesMut::with_capacity(16/8); + buf.put_u16_be(*self); + s.extend_buffer(&mut buf.to_vec()); + } +} impl Encodable for u32 { fn ssz_append(&self, s: &mut SszStream) { let mut buf = BytesMut::with_capacity(32/8); buf.put_u32_be(*self); - s.append_encoded_vec(&mut buf.to_vec()); + s.extend_buffer(&mut buf.to_vec()); } } @@ -88,13 +107,13 @@ impl Encodable for u64 { fn ssz_append(&self, s: &mut SszStream) { let mut buf = BytesMut::with_capacity(64/8); buf.put_u64_be(*self); - s.append_encoded_vec(&mut buf.to_vec()); + s.extend_buffer(&mut buf.to_vec()); } } impl Encodable for H256 { fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_vec(&mut self.to_vec()); + s.extend_buffer(&mut self.to_vec()); } } @@ -110,7 +129,7 @@ impl Encodable for U256 { #[cfg(test)] mod tests { use super::*; - + #[test] #[should_panic] fn test_encode_length_0_bytes_panic() { @@ -140,7 +159,7 @@ mod tests { vec![255, 255, 255, 255] ); } - + #[test] #[should_panic] fn test_encode_length_4_bytes_panic() { @@ -152,7 +171,7 @@ mod tests { pub struct TestStruct { pub one: u32, pub two: H256, - pub three: u64, + pub three: u64, } impl Encodable for TestStruct {