use super::*;
mod impls;
pub trait Encode {
fn is_sszb_fixed_len() -> bool;
fn sszb_append(&self, buf: &mut Vec<u8>);
fn sszb_fixed_len() -> usize {
BYTES_PER_LENGTH_OFFSET
}
fn sszb_bytes_len(&self) -> usize;
fn as_sszb_bytes(&self) -> Vec<u8> {
let mut buf = vec![];
self.sszb_append(&mut buf);
buf
}
}
pub struct SszEncoder<'a> {
offset: usize,
buf: &'a mut Vec<u8>,
variable_bytes: Vec<u8>,
}
impl<'a> SszEncoder<'a> {
pub fn container(buf: &'a mut Vec<u8>, num_fixed_bytes: usize) -> Self {
buf.reserve(num_fixed_bytes);
Self {
offset: num_fixed_bytes,
buf,
variable_bytes: vec![],
}
}
pub fn append<T: Encode>(&mut self, item: &T) {
self.append_parameterized(T::is_sszb_fixed_len(), |buf| item.sszb_append(buf))
}
pub fn append_parameterized<F>(&mut self, is_sszb_fixed_len: bool, sszb_append: F)
where
F: Fn(&mut Vec<u8>),
{
if is_sszb_fixed_len {
sszb_append(self.buf);
} else {
self.buf
.extend_from_slice(&encode_length(self.offset + self.variable_bytes.len()));
sszb_append(&mut self.variable_bytes);
}
}
pub fn finalize(&mut self) -> &mut Vec<u8> {
self.buf.append(&mut self.variable_bytes);
self.buf
}
}
pub fn encode_length(len: usize) -> [u8; BYTES_PER_LENGTH_OFFSET] {
debug_assert!(len <= MAX_LENGTH_VALUE);
let mut bytes = [0; BYTES_PER_LENGTH_OFFSET];
let lenb = len.to_be_bytes();
bytes.copy_from_slice(&lenb[lenb.len() - BYTES_PER_LENGTH_OFFSET..]);
bytes
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encode_length() {
assert_eq!(encode_length(0), [0; 4]);
assert_eq!(encode_length(1), [0, 0, 0, 1]);
assert_eq!(
encode_length(MAX_LENGTH_VALUE),
[255; BYTES_PER_LENGTH_OFFSET]
);
}
#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn test_encode_length_above_max_debug_panics() {
encode_length(MAX_LENGTH_VALUE + 1);
}
#[test]
#[cfg(not(debug_assertions))]
fn test_encode_length_above_max_not_debug_does_not_panic() {
assert_eq!(&encode_length(MAX_LENGTH_VALUE + 1)[..], &[0; 4]);
}
}