Skip to main content

zc_rlnc/primitives/
mod.rs

1//! RLNC primitives.
2pub mod field;
3pub mod packet;
4use field::Field;
5
6use crate::common::BOUNDARY_MARKER;
7
8/// A collection of equally sized, prepared chunks of data. Each chunk of data holds the symbols.
9/// This type represents correctly sized and padded chunks of data that are ready to be encoded.
10#[derive(Debug)]
11pub struct Chunks<F: Field> {
12    inner: Vec<Chunk<F>>,
13    chunk_size: usize,
14}
15
16/// Errors that can occur when creating a new collection of chunks.
17#[derive(Debug, thiserror::Error)]
18pub enum ChunksError {
19    /// The data is empty.
20    #[error("data is empty")]
21    EmptyData,
22    /// The chunk count is zero.
23    #[error("chunk count is zero")]
24    ZeroChunkCount,
25    /// The chunk size is zero.
26    #[error("chunk size is zero")]
27    ZeroChunkSize,
28}
29
30impl<F: Field> Chunks<F> {
31    /// Creates a new collection of chunks from a slice of bytes. The data is split into
32    /// `chunk_count` equally sized chunks, and then converted into symbols (scalars) of the
33    /// field `F`. See also [`Chunk`] for more details.
34    pub fn new(data: &[u8], chunk_count: usize) -> Result<Self, ChunksError> {
35        if data.is_empty() {
36            return Err(ChunksError::EmptyData);
37        }
38
39        if chunk_count == 0 {
40            return Err(ChunksError::ZeroChunkCount);
41        }
42
43        let mut data = Vec::from(data.as_ref());
44        data.push(BOUNDARY_MARKER);
45
46        // Calculate chunk size to accommodate original data + boundary marker
47        let chunk_size = data.len().div_ceil(chunk_count);
48
49        // Round up chunk size to nearest multiple of `F::SAFE_CAPACITY` for scalar packing
50        let chunk_size = chunk_size.div_ceil(F::SAFE_CAPACITY) * F::SAFE_CAPACITY;
51        let padded_len = chunk_size * chunk_count;
52
53        // Pad the rest with zeros if needed
54        data.resize(padded_len, 0);
55
56        let chunks = data.chunks_exact(chunk_size).map(Chunk::from_bytes).collect();
57
58        Ok(Self { inner: chunks, chunk_size })
59    }
60
61    /// Returns the size of the chunks in bytes.
62    pub fn chunk_size(&self) -> usize {
63        self.chunk_size
64    }
65
66    /// Returns the inner chunks.
67    pub fn inner(&self) -> &[Chunk<F>] {
68        &self.inner
69    }
70
71    /// Returns the number of chunks in the collection.
72    pub fn len(&self) -> usize {
73        self.inner.len()
74    }
75
76    /// Returns true if the collection is empty.
77    pub fn is_empty(&self) -> bool {
78        self.inner.is_empty()
79    }
80}
81
82/// A chunk of data.
83#[derive(Debug, Clone)]
84pub struct Chunk<F: Field> {
85    symbols: Vec<F>,
86    #[allow(unused)]
87    size: usize,
88}
89
90impl<F: Field> Chunk<F> {
91    /// Creates a new chunk from a slice of bytes, and converts it into a vector of scalars
92    /// (symbols used for encoding).
93    pub(crate) fn from_bytes(bytes: &[u8]) -> Self {
94        let size = bytes.len();
95        Self { symbols: bytes.chunks(F::SAFE_CAPACITY).map(|c| F::from_bytes(c)).collect(), size }
96    }
97
98    /// Returns the symbols of the chunk.
99    pub(crate) fn symbols(&self) -> &[F] {
100        &self.symbols
101    }
102}