Skip to main content

zc_rlnc/
decode.rs

1//! Module that implements the RLNC decoding algorithm.
2
3use crate::{
4    common::RLNCError,
5    matrix::Matrix,
6    primitives::{ChunksError, field::Field, packet::RLNCPacket},
7};
8
9/// RLNC Decoder.
10#[derive(Debug)]
11pub struct Decoder<F: Field> {
12    /// The size of each original chunk in bytes.
13    chunk_size: usize,
14    /// The number of coded packets required to decode the original data, also known as the
15    /// generation size.
16    chunk_count: usize,
17
18    /// The RREF matrix of received coded packets.
19    matrix: Matrix<F>,
20}
21
22impl<F: Field> Decoder<F> {
23    /// Creates a new decoder for the given chunk size and chunk count (generation size).
24    pub fn new(chunk_size: usize, chunk_count: usize) -> Result<Self, RLNCError> {
25        if chunk_size == 0 {
26            return Err(ChunksError::ZeroChunkSize.into());
27        }
28
29        if chunk_count == 0 {
30            return Err(RLNCError::ZeroPacketCount);
31        }
32
33        Ok(Self { chunk_size, chunk_count, matrix: Matrix::new(chunk_count) })
34    }
35
36    /// Decodes a coded packet. If the decoder has enough linearly independent packets, it will
37    /// return the original data.
38    pub fn decode(&mut self, packet: RLNCPacket<F>) -> Result<Option<Vec<u8>>, RLNCError> {
39        if packet.coding_vector.len() != self.chunk_count {
40            return Err(RLNCError::InvalidCodingVectorLength(
41                packet.coding_vector.len(),
42                self.chunk_count,
43            ));
44        }
45
46        if self.matrix.push_rref(packet) {
47            return Ok(Some(self.matrix.decode(self.chunk_size)?));
48        }
49
50        // Store the packet data separately - we need coding vectors and data separate
51        Ok(None)
52    }
53
54    /// Returns the number of linearly independent packets received.
55    #[inline]
56    pub const fn rank(&self) -> usize {
57        self.matrix.rank()
58    }
59
60    /// Returns true if the decoder can decode the original data (i.e. if the rank is equal to the
61    /// generation size).
62    #[inline]
63    pub const fn can_decode(&self) -> bool {
64        self.matrix.can_decode()
65    }
66}