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