1#[cfg(feature = "alloc")]
7extern crate alloc;
8
9use crate::aligned::AlignedBuffer;
10use crate::encoder::{CodedPacket, SimpleRng};
11use crate::error::RlncError;
12use crate::kernel;
13
14pub struct Recoder;
16
17impl Recoder {
18 #[cfg(feature = "alloc")]
22 pub fn recode(coded: &[CodedPacket], rng: &mut SimpleRng) -> Result<CodedPacket, RlncError> {
23 if coded.is_empty() {
24 return Err(RlncError::InvalidParameters);
25 }
26
27 let k = coded[0].coefficients.len();
28 let n = coded[0].payload.len();
29
30 for pkt in coded {
31 if pkt.coefficients.len() != k || pkt.payload.len() != n {
32 return Err(RlncError::PacketSizeMismatch {
33 expected_coeffs: k,
34 got_coeffs: pkt.coefficients.len(),
35 expected_payload: n,
36 got_payload: pkt.payload.len(),
37 });
38 }
39 }
40
41 let mut out_coeffs = AlignedBuffer::zeroed(k);
42 let mut out_payload = AlignedBuffer::zeroed(n);
43
44 let mut recode_coeffs = alloc::vec![0u8; coded.len()];
45 rng.fill(&mut recode_coeffs);
46 let mut retries = 0u32;
48 while recode_coeffs.iter().all(|&c| c == 0) {
49 retries += 1;
50 if retries >= 100 {
51 recode_coeffs[0] = 1;
52 break;
53 }
54 rng.fill(&mut recode_coeffs);
55 }
56
57 for (i, &rc) in recode_coeffs.iter().enumerate() {
58 if rc == 0 {
59 continue;
60 }
61 kernel::axpy(
62 rc,
63 coded[i].coefficients.as_slice(),
64 out_coeffs.as_mut_slice(),
65 );
66 kernel::axpy(rc, coded[i].payload.as_slice(), out_payload.as_mut_slice());
67 }
68
69 Ok(CodedPacket {
70 coefficients: out_coeffs,
71 payload: out_payload,
72 })
73 }
74}
75
76#[cfg(test)]
77#[cfg(feature = "alloc")]
78mod tests {
79 use super::*;
80 use crate::decoder::Decoder;
81 use crate::encoder::Encoder;
82
83 #[test]
84 fn recode_then_decode() {
85 let k = 4usize;
86 let n = 32usize;
87 let source: alloc::vec::Vec<alloc::vec::Vec<u8>> = (0..k)
88 .map(|i| alloc::vec![(i as u8).wrapping_mul(17); n])
89 .collect();
90 let refs: alloc::vec::Vec<&[u8]> = source.iter().map(Vec::as_slice).collect();
91
92 let enc = Encoder::new(k, n).unwrap();
93 let mut rng = SimpleRng::new(0x1234_5678);
94
95 let mut coded: alloc::vec::Vec<CodedPacket> = (0..k)
97 .map(|i| enc.encode_systematic(&refs, i).unwrap())
98 .collect();
99 for _ in 0..k {
100 coded.push(enc.encode_random(&refs, &mut rng).unwrap());
101 }
102
103 let mut dec = Decoder::new(k, n).unwrap();
104 let mut recode_rng = SimpleRng::new(0xABCD_EF01);
105 for _ in 0..k * 4 {
107 let recoded = Recoder::recode(&coded, &mut recode_rng).unwrap();
108 let _ = dec.receive(recoded);
109 if dec.is_complete() {
110 break;
111 }
112 }
113
114 assert!(
115 dec.is_complete(),
116 "recode stream never reached full rank (rank={})",
117 dec.rank()
118 );
119 let decoded = dec.decode().unwrap().expect("decode after complete");
120 assert_eq!(decoded.len(), k);
121 for i in 0..k {
122 assert_eq!(decoded[i], source[i], "symbol {i} mismatch after recode");
123 }
124 }
125
126 #[test]
127 fn recode_empty_is_invalid() {
128 let mut rng = SimpleRng::new(1);
129 let err = Recoder::recode(&[], &mut rng).unwrap_err();
130 assert_eq!(err, RlncError::InvalidParameters);
131 }
132
133 #[test]
134 fn recode_size_mismatch() {
135 let mut rng = SimpleRng::new(2);
136 let a = CodedPacket::from_slices(&[1, 0], &[9, 9]);
137 let b = CodedPacket::from_slices(&[0, 1, 0], &[8, 8]); let err = Recoder::recode(&[a, b], &mut rng).unwrap_err();
139 match err {
140 RlncError::PacketSizeMismatch { .. } => {}
141 other => panic!("expected PacketSizeMismatch, got {other:?}"),
142 }
143 }
144}