use super::consts::BOUNDARY_MARKER;
use crate::{RLNCError, full::decoder_matrix::DecoderMatrix};
#[derive(Clone, Debug)]
pub struct Decoder {
matrix: DecoderMatrix,
piece_byte_len: usize,
required_piece_count: usize,
received_piece_count: usize,
useful_piece_count: usize,
}
impl Decoder {
pub fn get_num_pieces_coded_together(&self) -> usize {
self.required_piece_count
}
pub fn get_piece_byte_len(&self) -> usize {
self.piece_byte_len
}
pub fn get_full_coded_piece_byte_len(&self) -> usize {
self.get_num_pieces_coded_together() + self.get_piece_byte_len()
}
pub fn get_received_piece_count(&self) -> usize {
self.received_piece_count
}
pub fn get_useful_piece_count(&self) -> usize {
self.useful_piece_count
}
pub fn get_remaining_piece_count(&self) -> usize {
self.get_num_pieces_coded_together() - self.get_useful_piece_count()
}
pub fn new(piece_byte_len: usize, required_piece_count: usize) -> Result<Decoder, RLNCError> {
if piece_byte_len == 0 {
return Err(RLNCError::PieceLengthZero);
}
if required_piece_count == 0 {
return Err(RLNCError::PieceCountZero);
}
Ok(Decoder {
matrix: DecoderMatrix::new(required_piece_count, piece_byte_len),
piece_byte_len,
required_piece_count,
received_piece_count: 0,
useful_piece_count: 0,
})
}
pub fn decode(&mut self, full_coded_piece: &[u8]) -> Result<(), RLNCError> {
if self.is_already_decoded() {
return Err(RLNCError::ReceivedAllPieces);
}
if full_coded_piece.len() != self.get_full_coded_piece_byte_len() {
return Err(RLNCError::InvalidPieceLength);
}
let rank_before = self.matrix.rank();
unsafe { self.matrix.add_row(full_coded_piece).unwrap_unchecked().rref() };
self.received_piece_count += 1;
let rank_after = self.matrix.rank();
if rank_before == rank_after {
Err(RLNCError::PieceNotUseful)
} else {
self.useful_piece_count = rank_after;
Ok(())
}
}
pub fn is_already_decoded(&self) -> bool {
self.matrix.rank() == self.required_piece_count
}
pub fn get_decoded_data(self) -> Result<Vec<u8>, RLNCError> {
if !self.is_already_decoded() {
return Err(RLNCError::NotAllPiecesReceivedYet);
}
let required_len = self.piece_byte_len * self.required_piece_count;
let mut buf = vec![0u8; required_len];
let mut current_pos = 0;
let full_coded_piece_len = self.get_full_coded_piece_byte_len();
for chunk in self.matrix.extract_data().chunks_exact(full_coded_piece_len) {
let payload = &chunk[self.required_piece_count..];
let end_pos = current_pos + self.piece_byte_len;
buf[current_pos..end_pos].copy_from_slice(payload);
current_pos = end_pos;
}
let final_len = Self::get_final_data_len(&buf[..current_pos])?;
buf.truncate(final_len);
Ok(buf)
}
fn get_final_data_len(padded_data: &[u8]) -> Result<usize, RLNCError> {
let last_index = padded_data.len().saturating_sub(1);
let boundary_marker_rev_index = padded_data.iter().rev().position(|&byte| byte == BOUNDARY_MARKER).unwrap_or(last_index);
let boundary_marker_index = last_index - boundary_marker_rev_index;
if boundary_marker_index == 0 {
return Err(RLNCError::InvalidDecodedDataFormat);
}
if padded_data[(boundary_marker_index + 1)..].iter().any(|&byte| byte != 0) {
return Err(RLNCError::InvalidDecodedDataFormat);
}
Ok(boundary_marker_index)
}
}
#[cfg(test)]
mod tests {
use super::{Decoder, RLNCError};
use crate::full::encoder::Encoder;
use rand::Rng;
#[test]
fn test_decoder_new_invalid_inputs() {
let piece_byte_len_zero = 0;
let required_piece_count_non_zero = 10;
let result_piece_len_zero = Decoder::new(piece_byte_len_zero, required_piece_count_non_zero);
assert!(result_piece_len_zero.is_err());
assert_eq!(result_piece_len_zero.expect_err("Expected PieceLengthZero error"), RLNCError::PieceLengthZero);
let piece_byte_len_non_zero = 10;
let required_piece_count_zero = 0;
let result_piece_count_zero = Decoder::new(piece_byte_len_non_zero, required_piece_count_zero);
assert!(result_piece_count_zero.is_err());
assert_eq!(result_piece_count_zero.expect_err("Expected PieceCountZero error"), RLNCError::PieceCountZero);
let piece_byte_len_both_zero = 0;
let required_piece_count_both_zero = 0;
let result_both_zero = Decoder::new(piece_byte_len_both_zero, required_piece_count_both_zero);
assert!(result_both_zero.is_err());
assert_eq!(
result_both_zero.expect_err("Expected PieceLengthZero error for both zero inputs"),
RLNCError::PieceLengthZero
);
let piece_byte_len_valid = 10;
let required_piece_count_valid = 5;
let result_valid = Decoder::new(piece_byte_len_valid, required_piece_count_valid);
assert!(result_valid.is_ok());
}
#[test]
fn test_decoder_decode_invalid_piece_length() {
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 decode invalid length test");
let piece_byte_len = encoder.get_piece_byte_len();
let required_piece_count = encoder.get_piece_count();
let full_coded_piece_byte_len = encoder.get_full_coded_piece_byte_len();
let mut decoder = Decoder::new(piece_byte_len, required_piece_count).expect("Failed to create Decoder for decode invalid length test");
let short_piece_len = full_coded_piece_byte_len - 1;
let short_coded_piece: Vec<u8> = (0..short_piece_len).map(|_| rng.random()).collect();
let result_short = decoder.decode(&short_coded_piece);
assert!(result_short.is_err());
assert_eq!(
result_short.expect_err("Expected InvalidPieceLength error for short piece"),
RLNCError::InvalidPieceLength
);
let long_piece_len = full_coded_piece_byte_len + 1;
let long_coded_piece: Vec<u8> = (0..long_piece_len).map(|_| rng.random()).collect();
let result_long = decoder.decode(&long_coded_piece);
assert!(result_long.is_err());
assert_eq!(
result_long.expect_err("Expected InvalidPieceLength error for long piece"),
RLNCError::InvalidPieceLength
);
let zero_piece: Vec<u8> = Vec::new();
let result_zero = decoder.decode(&zero_piece);
assert!(result_zero.is_err());
assert_eq!(
result_zero.expect_err("Expected InvalidPieceLength error for zero-length piece"),
RLNCError::InvalidPieceLength
);
assert_eq!(decoder.get_received_piece_count(), 0);
assert_eq!(decoder.get_useful_piece_count(), 0);
assert!(!decoder.is_already_decoded());
let correct_coded_piece = encoder.code(&mut rng);
let result_correct = decoder.decode(&correct_coded_piece);
assert!(result_correct.is_ok() || matches!(result_correct, Err(RLNCError::PieceNotUseful)));
assert_eq!(decoder.get_received_piece_count(), 1);
if result_correct.is_ok() {
assert_eq!(decoder.get_useful_piece_count(), 1);
assert!(!decoder.is_already_decoded()); } else {
assert_eq!(decoder.get_useful_piece_count(), 0);
}
}
#[test]
fn test_decoder_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.clone(), piece_count).expect("Failed to create Encoder for getters test");
let piece_byte_len = encoder.get_piece_byte_len();
let required_piece_count = encoder.get_piece_count();
let full_coded_piece_byte_len = encoder.get_full_coded_piece_byte_len();
let mut decoder = Decoder::new(piece_byte_len, required_piece_count).expect("Failed to create Decoder for getters test");
assert_eq!(decoder.get_num_pieces_coded_together(), required_piece_count);
assert_eq!(decoder.get_piece_byte_len(), piece_byte_len);
assert_eq!(decoder.get_full_coded_piece_byte_len(), full_coded_piece_byte_len);
assert_eq!(decoder.get_received_piece_count(), 0);
assert_eq!(decoder.get_useful_piece_count(), 0);
assert_eq!(decoder.get_remaining_piece_count(), required_piece_count);
assert!(!decoder.is_already_decoded());
let num_pieces_to_decode_initially = required_piece_count / 2;
let mut expected_useful_pieces_after_initial = 0;
for _ in 0..num_pieces_to_decode_initially {
let coded_piece = encoder.code(&mut rng);
match decoder.decode(&coded_piece) {
Ok(_) => {
expected_useful_pieces_after_initial += 1;
}
Err(RLNCError::PieceNotUseful) => {}
Err(e) => panic!("Unexpected error during initial decoding phase: {e:?}"),
}
}
assert_eq!(decoder.get_received_piece_count(), num_pieces_to_decode_initially);
assert_eq!(decoder.get_useful_piece_count(), expected_useful_pieces_after_initial);
assert_eq!(decoder.get_remaining_piece_count(), required_piece_count - expected_useful_pieces_after_initial);
let mut total_pieces_received = num_pieces_to_decode_initially;
while !decoder.is_already_decoded() {
let coded_piece = encoder.code(&mut rng);
match decoder.decode(&coded_piece) {
Ok(_) => {}
Err(RLNCError::PieceNotUseful) => {}
Err(RLNCError::ReceivedAllPieces) => break,
Err(e) => panic!("Unexpected error during final decoding phase: {e:?}"),
}
total_pieces_received += 1;
}
assert_eq!(decoder.get_useful_piece_count(), required_piece_count);
assert_eq!(decoder.get_remaining_piece_count(), 0);
assert!(decoder.is_already_decoded());
assert_eq!(decoder.get_received_piece_count(), total_pieces_received);
}
}