use alloc::vec::Vec;
use crate::partition::Partition;
use crate::{common, raptor};
pub struct SourceBlockEncoder {
intermediate: Vec<Vec<u8>>,
source_symbols: Vec<Vec<u8>>,
k: u32,
l: u32,
l_prime: u32,
}
impl SourceBlockEncoder {
pub fn new(source_block: &[u8], max_source_symbols: usize) -> Result<Self, &'static str> {
let partition = Partition::new(source_block.len(), max_source_symbols);
let source_block = partition.create_source_block(source_block);
let k = source_block.len() as u32;
let source_symbols: Vec<Vec<u8>> =
source_block.iter().map(|s| s.data.to_vec()).collect();
let mut raptor = raptor::Raptor::new(k);
let fully_specified = raptor.add_encoding_symbols(&source_block);
if !fully_specified {
if k < 4 {
return Err("Source Block is partitionned in too few encoding symbols (k < 4), Raptor matrix is not fully specified");
}
return Err("Raptor matrix is not fully specified");
}
raptor.reduce();
Ok(SourceBlockEncoder {
intermediate: raptor.intermediate_symbols().to_vec(),
source_symbols,
k,
l: raptor.get_l(),
l_prime: raptor.get_l_prime(),
})
}
pub fn nb_source_symbols(&self) -> u32 {
self.k
}
pub fn fountain(&mut self, esi: u32) -> Vec<u8> {
if esi < self.k {
return self.source_symbols[esi as usize].clone();
}
let mut block = Vec::new();
let indices = common::find_lt_indices(self.k, esi, self.l, self.l_prime);
for indice in indices {
if indice < self.intermediate.len() as u32 {
common::xor(&mut block, &self.intermediate[indice as usize]);
}
}
block
}
}
pub fn encode_source_block(
source_block: &[u8],
max_source_symbols: usize,
nb_repair: usize,
) -> Result<(Vec<Vec<u8>>, u32), &'static str> {
let mut encoder = SourceBlockEncoder::new(source_block, max_source_symbols)?;
let mut output: Vec<Vec<u8>> = Vec::new();
let n = encoder.nb_source_symbols() as usize + nb_repair;
for esi in 0..n as u32 {
output.push(encoder.fountain(esi));
}
Ok((output, encoder.nb_source_symbols()))
}
#[cfg(test)]
mod tests {
use alloc::vec;
use alloc::vec::Vec;
#[test]
fn test_source_block_encoder() {
crate::tests::init();
let input: Vec<u8> = vec![1, 2, 7, 4, 0, 2, 54, 4, 1, 1, 10, 200, 1, 21, 3, 80];
let max_source_symbols = 4;
let nb_repair = 3;
let (encoded_block, k) =
super::encode_source_block(&input, max_source_symbols, nb_repair).unwrap();
log::debug!("Encoded with {} blocks", k);
let mut encoded_block: Vec<Option<Vec<u8>>> = encoded_block
.into_iter()
.map(|symbols| Some(symbols))
.collect();
encoded_block[0] = None;
encoded_block[1] = None;
let output =
crate::decoder::decode_source_block(&encoded_block, k as usize, input.len()).unwrap();
log::debug!("{:?} / {:?}", output, input);
assert!(output.len() == input.len());
assert!(output == input);
}
}