1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! # rlnc: Random Linear Network Coding
//!
//! `rlnc` is a Rust library that provides an implementation of Random Linear Network Coding (RLNC) over finite field $GF(2^8)$.
//!
//! At source, data owner creates encoded (i.e. erasure-coded) pieces by computing random linear combinations of
//! original data (always padded to ensure safe decoding) split into smaller pieces using random sampled coding coefficients.
//! These erasure-coded pieces, tagged with random coding vectors, are forwarded to peers.
//!
//! Intermediate nodes in the network can combine any number of coded pieces to create new coded pieces, without
//! ever decoding to original data. This is where recoder comes into play. And one of the reasons why RLNC shines
//! as an advanced erasure-coding technique.
//!
//! Receiving nodes decode the original data by collecting enough linearly independent combinations to solve
//! the linear system of equations i.e. nothing but the source pieces. This is the most compute-intensive part of RLNC.
//! And this is also the slowest part of RLNC, orders of magnitude slower compared to encoder and recoder.
//!
//! RLNC enhances network throughput, robustness, and efficiency, particularly in lossy or dynamic networks.
//! It can be used in applications like video streaming, distributed storage, and satellite communications,
//! improving reliability and reducing latency. In RLNC each erasure-coded piece is equally important to the decoder,
//! hence order of received pieces do not matter.
//!
//! ## How it Works
//!
//! At its core, RLNC works by mixing original data pieces into new "coded pieces"
//! using random linear combinations over $GF(2^8)$.
//!
//! The main components of this library are:
//!
//! - **`Encoder`**: Takes the original data, pads it properly, splits it into fixed-size pieces,
//! and generates new coded pieces by applying random linear combinations.
//! Each coded piece includes a coding vector and the linearly combined data.
//! The encoder handles necessary padding and a boundary marker is inserted to ensure
//! correct data recovery post decoding.
//!
//! - **`Recoder`**: A crucial feature of network coding. A recoder takes
//! already coded pieces as input and generates *new* coded pieces from them.
//! This allows intermediate nodes in a network to participate in erasure-coding process,
//! recoding without first decoding it to the original form, significantly improving
//! throughput and robustness in complex network topologies.
//!
//! - **`Decoder`**: Receives coded pieces and attempts to reconstruct the original data.
//! It employs repeated Gaussian elimination to decode received pieces. As soon as enough
//! linearly independent pieces are received, it can reconstruct the original data, regardless
//! of which specific pieces were lost or received, in whichever order.
//!
//! ## Features
//!
//! - **Flexible data handling**: Supports arbitrary byte lengths for input
//! data, with internal padding and boundary markers for robust decoding.
//! - **Error Handling**: Comprehensive `RLNCError` enum for various failure scenarios.
//!
//! ## Example Usage
//!
//! A typical workflow involves creating an `Encoder` with your original data,
//! generating arbitrary many coded pieces, sending them across a network (potentially through `Recoder`s),
//! and finally, using a `Decoder` to reconstruct the original data.
//!
//! ```rust
//! use rand::Rng;
//! use rlnc::{
//! RLNCError,
//! full::{Decoder, Encoder, Recoder},
//! };
//!
//! let mut rng = rand::rng();
//!
//! // 1. Define original data parameters
//! let original_data_len = 10 * 1024; // 10 KB
//! let piece_count = 32; // Data will be split into 32 pieces
//! let num_pieces_for_recoding = piece_count / 2; // For recoding, 16 coded pieces to be used
//! let original_data: Vec<u8> = (0..original_data_len).map(|_| rng.random()).collect();
//! let original_data_copy = original_data.clone();
//!
//! // 2. Initialize the Encoder
//! let encoder = Encoder::new(original_data, piece_count).expect("Failed to create RLNC encoder");
//!
//! // 3. Generate 16 coded-pieces, to be used by the Recoder for producing new coded pieces.
//! let coded_pieces_for_recoding: Vec<u8> = (0..num_pieces_for_recoding).flat_map(|_| encoder.code(&mut rng)).collect();
//!
//! // 4. Initialize the Recoder with 16 coded pieces
//! let mut recoder = Recoder::new(coded_pieces_for_recoding, encoder.get_full_coded_piece_byte_len(), encoder.get_piece_count()).expect("Failed to create RLNC recoder");
//!
//! // 5. Initialize the Decoder
//! let mut decoder = Decoder::new(encoder.get_piece_byte_len(), encoder.get_piece_count()).expect("Failed to create RLNC decoder");
//!
//! // 6. Generate a recoded piece, this is the piece to be sent to the decoder as first piece.
//! let recoded_piece = recoder.recode(&mut rng);
//!
//! // 7. First coded piece injected into the Decoder - it should be useful
//! decoder.decode(&recoded_piece).expect("First coded piece should be useful");
//!
//! // 8. Generate coded pieces directly from the encoder and feed them to the decoder until decoding is complete
//! while !decoder.is_already_decoded() {
//! let coded_piece = encoder.code(&mut rng);
//!
//! match decoder.decode(&coded_piece) {
//! Ok(_) => {}, // Piece was useful
//! Err(RLNCError::PieceNotUseful) => {}, // Piece was not useful (linearly dependent)
//! Err(RLNCError::ReceivedAllPieces) => break, // Already decoded
//! Err(e) => panic!("Unexpected error during decoding: {e:?}"),
//! }
//! }
//!
//! // 5. Retrieve the decoded data
//! let decoded_data = decoder.get_decoded_data().expect("Failed to retrieve decoded data even after all pieces are received");
//!
//! // 6. Verify that the decoded data matches the original data
//! assert_eq!(original_data_copy, decoded_data);
//! println!("RLNC workflow completed successfully! Original data matches decoded data.");
//! ```
//!
//! ## Installation
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! rlnc = "=0.8.7" # On x86_64 and aarch64 targets, it offers fast encoding, recoding and decoding, using SIMD intrinsics.
//! # or
//! rlnc = { version = "=0.8.7", features = "parallel" } # Uses `rayon`-based data-parallelism for fast encoding/ recoding. Decoding is not yet parallelized.
//!
//! rand = { version = "=0.9.1" } # Required for random number generation
//! ```
//!
//! For more see README in `rlnc` repository @ <https://github.com/itzmeanjan/rlnc>.
pub use crateRLNCError;