use reed_solomon_erasure::ReedSolomon;
use smallvec::SmallVec;
use sbx_block;
use sbx_specs::{Version,
SBX_LARGEST_BLOCK_SIZE,
ver_to_block_size,
ver_uses_rs};
pub struct RSEncoder {
index : usize,
rs_codec : ReedSolomon,
version : Version,
par_buf : SmallVec<[SmallVec<[u8; SBX_LARGEST_BLOCK_SIZE]>; 32]>,
active : bool,
}
macro_rules! mark_active {
(
$self:ident
) => {{
$self.active = true;
}}
}
macro_rules! mark_inactive {
(
$self:ident
) => {{
$self.active = false;
}}
}
macro_rules! incre_index {
(
$self:ident
) => {{
$self.index += 1;
}}
}
macro_rules! reset_index {
(
$self:ident
) => {{
$self.index = 0;
}}
}
macro_rules! codec_ready {
(
$self:ident
) => {{
$self.index == $self.rs_codec.data_shard_count()
}}
}
impl RSEncoder {
pub fn new(version : Version,
data_shards : usize,
parity_shards : usize) -> RSEncoder {
assert!(ver_uses_rs(version));
let block_size = ver_to_block_size(version);
let par_buf : SmallVec<[SmallVec<[u8; SBX_LARGEST_BLOCK_SIZE]>; 32]> =
smallvec![smallvec![0; block_size]; parity_shards];
RSEncoder {
index : 0,
rs_codec : ReedSolomon::new(data_shards,
parity_shards).unwrap(),
version,
par_buf,
active : false,
}
}
pub fn active(&self) -> bool {
self.active
}
pub fn unfilled_slot_count(&self) -> usize {
self.total_slot_count() - self.index
}
pub fn total_slot_count(&self) -> usize {
self.rs_codec.data_shard_count()
}
pub fn encode_no_block_sync(&mut self,
data : &[u8])
-> Option<&mut SmallVec<[SmallVec<[u8; SBX_LARGEST_BLOCK_SIZE]>; 32]>> {
let data = sbx_block::slice_data_buf(self.version, data);
let version = self.version;
let rs_codec = &self.rs_codec;
let par_buf = &mut self.par_buf;
{
let mut parity : SmallVec<[&mut [u8]; 32]> =
SmallVec::with_capacity(par_buf.len());
for p in par_buf.iter_mut() {
parity.push(sbx_block::slice_data_buf_mut(version, p));
}
rs_codec.encode_single_sep(self.index,
data,
&mut parity).unwrap();
}
incre_index!(self);
if codec_ready!(self) {
reset_index!(self);
mark_inactive!(self);
Some(par_buf)
} else {
mark_active!(self);
None
}
}
}