use super::encoder::Encoder;
use crate::{RLNCError, common::gf256::Gf256};
use rand::Rng;
#[derive(Clone, Debug)]
pub struct Recoder {
coding_vectors: Vec<Gf256>,
encoder: Encoder,
num_pieces_received: usize,
full_coded_piece_byte_len: usize,
num_pieces_coded_together: usize,
random_recoding_vector: Vec<u8>,
}
impl Recoder {
pub fn get_original_num_pieces_coded_together(&self) -> usize {
self.num_pieces_coded_together
}
pub fn get_num_pieces_recoded_together(&self) -> usize {
self.num_pieces_received
}
pub fn get_piece_byte_len(&self) -> usize {
self.full_coded_piece_byte_len - self.num_pieces_coded_together
}
pub fn get_full_coded_piece_byte_len(&self) -> usize {
self.full_coded_piece_byte_len
}
pub fn new(data: Vec<u8>, full_coded_piece_byte_len: usize, num_pieces_coded_together: usize) -> Result<Recoder, RLNCError> {
if data.is_empty() {
return Err(RLNCError::NotEnoughPiecesToRecode);
}
if full_coded_piece_byte_len == 0 {
return Err(RLNCError::PieceLengthZero);
}
if num_pieces_coded_together == 0 {
return Err(RLNCError::PieceCountZero);
}
if full_coded_piece_byte_len <= num_pieces_coded_together {
return Err(RLNCError::PieceLengthTooShort);
}
let piece_byte_len = full_coded_piece_byte_len - num_pieces_coded_together;
let num_pieces_received = data.len() / full_coded_piece_byte_len;
let mut coding_vectors = Vec::with_capacity(num_pieces_received * num_pieces_coded_together);
let mut coded_pieces = Vec::with_capacity(num_pieces_received * piece_byte_len);
data.chunks_exact(full_coded_piece_byte_len).for_each(|full_coded_piece| {
let coding_vector = &full_coded_piece[..num_pieces_coded_together];
let coded_piece = &full_coded_piece[num_pieces_coded_together..];
coding_vectors.extend(coding_vector.iter().map(|&symbol| Gf256::new(symbol)));
coded_pieces.extend_from_slice(coded_piece);
});
let encoder = unsafe { Encoder::without_padding(coded_pieces, num_pieces_received).unwrap_unchecked() };
let random_recoding_vector = vec![0u8; num_pieces_received];
Ok(Recoder {
coding_vectors,
encoder,
num_pieces_received,
full_coded_piece_byte_len,
num_pieces_coded_together,
random_recoding_vector,
})
}
pub fn recode_with_buf<R: Rng + ?Sized>(&mut self, rng: &mut R, full_recoded_piece: &mut [u8]) -> Result<(), RLNCError> {
if full_recoded_piece.len() != self.full_coded_piece_byte_len {
return Err(RLNCError::InvalidOutputBuffer);
}
let (computed_coding_vector, recoded_data) = full_recoded_piece.split_at_mut(self.num_pieces_coded_together);
rng.fill_bytes(&mut self.random_recoding_vector);
for (coeff_idx, coeff_val) in computed_coding_vector.iter_mut().enumerate().take(self.num_pieces_coded_together) {
let computed_coeff = self
.random_recoding_vector
.iter()
.enumerate()
.fold(Gf256::default(), |acc, (recoding_vec_idx, &cur)| {
let row_begins_at = recoding_vec_idx * self.num_pieces_coded_together;
acc + Gf256::new(cur) * self.coding_vectors[row_begins_at + coeff_idx]
});
*coeff_val = computed_coeff.get();
}
unsafe {
self.encoder
.code_with_coding_vector(&self.random_recoding_vector, recoded_data)
.unwrap_unchecked()
};
Ok(())
}
pub fn recode<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Vec<u8> {
let mut full_recoded_piece = vec![0u8; self.get_full_coded_piece_byte_len()];
unsafe { self.recode_with_buf(rng, &mut full_recoded_piece).unwrap_unchecked() }
full_recoded_piece
}
}
#[cfg(test)]
mod tests {
use super::{RLNCError, Recoder};
use crate::full::encoder::Encoder;
use rand::Rng;
#[test]
fn test_recoder_new_invalid_inputs() {
let mut rng = rand::rng();
let data_byte_len = 1024usize;
let piece_count = 32usize;
let encoder = Encoder::new((0..data_byte_len).map(|_| rng.random()).collect::<Vec<u8>>(), piece_count)
.expect("Failed to create Encoder for recoder new invalid inputs test");
let full_coded_piece_byte_len = encoder.get_full_coded_piece_byte_len();
let num_pieces_coded_together = encoder.get_piece_count();
let empty_data: Vec<u8> = Vec::new();
let result_empty_data = Recoder::new(empty_data, full_coded_piece_byte_len, num_pieces_coded_together);
assert!(result_empty_data.is_err());
assert_eq!(
result_empty_data.expect_err("Expected NotEnoughPiecesToRecode error for empty data"),
RLNCError::NotEnoughPiecesToRecode
);
let data_non_empty = vec![1, 2, 3]; let result_zero_full_len = Recoder::new(data_non_empty.clone(), 0, num_pieces_coded_together);
assert!(result_zero_full_len.is_err());
assert_eq!(
result_zero_full_len.expect_err("Expected PieceLengthZero error for zero full coded piece length"),
RLNCError::PieceLengthZero
);
let result_zero_piece_count = Recoder::new(data_non_empty.clone(), full_coded_piece_byte_len, 0);
assert!(result_zero_piece_count.is_err());
assert_eq!(
result_zero_piece_count.expect_err("Expected PieceCountZero error for zero pieces coded together"),
RLNCError::PieceCountZero
);
let result_equal_len = Recoder::new(
data_non_empty.clone(),
num_pieces_coded_together, num_pieces_coded_together,
);
assert!(result_equal_len.is_err());
assert_eq!(
result_equal_len.expect_err("Expected PieceLengthTooShort error when full length equals piece count"),
RLNCError::PieceLengthTooShort
);
let result_less_len = Recoder::new(
data_non_empty.clone(),
num_pieces_coded_together - 1, num_pieces_coded_together,
);
assert!(result_less_len.is_err());
assert_eq!(
result_less_len.expect_err("Expected PieceLengthTooShort error when full length is less than piece count"),
RLNCError::PieceLengthTooShort
);
let num_pieces_to_recode_with = 5;
let coded_pieces_for_recoder: Vec<u8> = (0..num_pieces_to_recode_with).flat_map(|_| encoder.code(&mut rng)).collect();
let result_valid = Recoder::new(coded_pieces_for_recoder, full_coded_piece_byte_len, num_pieces_coded_together);
assert!(result_valid.is_ok());
let recoder = result_valid.expect("Expected Recoder to be created successfully with valid inputs");
assert_eq!(recoder.get_original_num_pieces_coded_together(), num_pieces_coded_together);
assert_eq!(recoder.get_num_pieces_recoded_together(), num_pieces_to_recode_with);
}
#[test]
fn test_recoder_recode_with_buf_invalid_inputs() {
let mut rng = rand::rng();
let data_byte_len = 1024usize;
let piece_count = 32usize;
let num_pieces_to_recode_with = piece_count / 2;
let data = (0..data_byte_len).map(|_| rng.random()).collect::<Vec<u8>>();
let encoder = Encoder::new(data, piece_count).expect("Failed to create Encoder for invalid inputs test");
let coded_pieces_for_recoder: Vec<u8> = (0..num_pieces_to_recode_with).flat_map(|_| encoder.code(&mut rng)).collect();
let mut recoder = Recoder::new(coded_pieces_for_recoder, encoder.get_full_coded_piece_byte_len(), encoder.get_piece_count())
.expect("Failed to create Recoder for invalid inputs test");
let mut short_recoded_piece = vec![0u8; recoder.get_full_coded_piece_byte_len() - 1];
let result_short = recoder.recode_with_buf(&mut rng, &mut short_recoded_piece);
assert!(result_short.is_err());
assert_eq!(
result_short.expect_err("Expected InvalidOutputBuffer error for short recoded piece buffer"),
RLNCError::InvalidOutputBuffer
);
let mut long_recoded_piece = vec![0u8; recoder.get_full_coded_piece_byte_len() + 1];
let result_long = recoder.recode_with_buf(&mut rng, &mut long_recoded_piece);
assert!(result_long.is_err());
assert_eq!(
result_long.expect_err("Expected InvalidOutputBuffer error for long recoded piece buffer"),
RLNCError::InvalidOutputBuffer
);
let mut empty_recoded_piece: Vec<u8> = vec![];
let result_empty = recoder.recode_with_buf(&mut rng, &mut empty_recoded_piece);
assert!(result_empty.is_err());
assert_eq!(
result_empty.expect_err("Expected InvalidOutputBuffer error for empty recoded piece buffer"),
RLNCError::InvalidOutputBuffer
);
let mut recoded_piece = vec![0u8; encoder.get_full_coded_piece_byte_len()];
let result_valid = recoder.recode_with_buf(&mut rng, &mut recoded_piece);
assert!(result_valid.is_ok());
}
#[test]
fn test_recoder_getters() {
let mut rng = rand::rng();
let data_byte_len = 1024usize;
let piece_count = 32usize; let data = (0..data_byte_len).map(|_| rng.random()).collect::<Vec<u8>>();
let encoder = Encoder::new(data, piece_count).expect("Failed to create Encoder for recoder getters test");
let num_pieces_to_recode_with = 10; let full_coded_piece_byte_len = encoder.get_full_coded_piece_byte_len();
let original_piece_byte_len = encoder.get_piece_byte_len();
let coded_pieces_for_recoder: Vec<u8> = (0..num_pieces_to_recode_with).flat_map(|_| encoder.code(&mut rng)).collect();
let recoder = Recoder::new(
coded_pieces_for_recoder,
full_coded_piece_byte_len,
piece_count, )
.expect("Recoder creation failed");
assert_eq!(recoder.get_original_num_pieces_coded_together(), piece_count);
assert_eq!(recoder.get_num_pieces_recoded_together(), num_pieces_to_recode_with);
assert_eq!(recoder.get_piece_byte_len(), original_piece_byte_len);
assert_eq!(recoder.get_full_coded_piece_byte_len(), full_coded_piece_byte_len);
}
}