reed_solomon_simd/
decoder_result.rs

1use crate::rate::DecoderWork;
2
3// ======================================================================
4// DecoderResult - PUBLIC
5
6/// Result of decoding. Contains the restored original shards.
7///
8/// This struct is created by [`ReedSolomonDecoder::decode`]
9/// and [`RateDecoder::decode`].
10///
11/// [`RateDecoder::decode`]: crate::rate::RateDecoder::decode
12/// [`ReedSolomonDecoder::decode`]: crate::ReedSolomonDecoder::decode
13pub struct DecoderResult<'a> {
14    work: &'a mut DecoderWork,
15}
16
17impl DecoderResult<'_> {
18    /// Returns restored original shard with given `index`
19    /// or `None` if given `index` doesn't correspond to
20    /// a missing original shard.
21    pub fn restored_original(&self, index: usize) -> Option<&[u8]> {
22        self.work.restored_original(index)
23    }
24
25    /// Returns iterator over all restored original shards
26    /// and their indexes, ordered by indexes.
27    pub fn restored_original_iter(&self) -> RestoredOriginal<'_> {
28        RestoredOriginal::new(self.work)
29    }
30}
31
32// ======================================================================
33// DecoderResult - CRATE
34
35impl<'a> DecoderResult<'a> {
36    pub(crate) fn new(work: &'a mut DecoderWork) -> Self {
37        Self { work }
38    }
39}
40
41// ======================================================================
42// DecoderResult - IMPL DROP
43
44impl Drop for DecoderResult<'_> {
45    fn drop(&mut self) {
46        self.work.reset_received();
47    }
48}
49
50// ======================================================================
51// RestoredOriginal - PUBLIC
52
53/// Iterator over restored original shards and their indexes.
54///
55/// This struct is created by [`DecoderResult::restored_original_iter`].
56pub struct RestoredOriginal<'a> {
57    remaining: usize,
58    next_index: usize,
59    work: &'a DecoderWork,
60}
61
62// ======================================================================
63// RestoredOriginal - IMPL Iterator
64
65impl<'a> Iterator for RestoredOriginal<'a> {
66    type Item = (usize, &'a [u8]);
67    fn next(&mut self) -> Option<(usize, &'a [u8])> {
68        if self.remaining == 0 {
69            return None;
70        }
71
72        let mut index = self.next_index;
73        while index < self.work.original_count() {
74            if let Some(original) = self.work.restored_original(index) {
75                self.next_index = index + 1;
76                self.remaining -= 1;
77                return Some((index, original));
78            }
79            index += 1;
80        }
81
82        debug_assert!(
83            false,
84            "Inconsistency in internal data structures. Please report."
85        );
86
87        None
88    }
89
90    fn size_hint(&self) -> (usize, Option<usize>) {
91        (self.remaining, Some(self.remaining))
92    }
93}
94
95// ======================================================================
96// RestoredOriginal - IMPL ExactSizeIterator
97
98impl ExactSizeIterator for RestoredOriginal<'_> {}
99
100// ======================================================================
101// RestoredOriginal - CRATE
102
103impl<'a> RestoredOriginal<'a> {
104    pub(crate) fn new(work: &'a DecoderWork) -> Self {
105        Self {
106            remaining: work.missing_original_count(),
107            next_index: 0,
108            work,
109        }
110    }
111}
112
113// ======================================================================
114// TESTS
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119    use crate::{test_util, ReedSolomonDecoder, ReedSolomonEncoder};
120
121    #[cfg(not(feature = "std"))]
122    use alloc::vec::Vec;
123
124    fn simple_roundtrip(shard_size: usize) {
125        let original = test_util::generate_original(3, shard_size, 0);
126
127        let mut encoder = ReedSolomonEncoder::new(3, 2, shard_size).unwrap();
128        let mut decoder = ReedSolomonDecoder::new(3, 2, shard_size).unwrap();
129
130        for original in &original {
131            encoder.add_original_shard(original).unwrap();
132        }
133
134        let result = encoder.encode().unwrap();
135        let recovery: Vec<_> = result.recovery_iter().collect();
136
137        assert!(recovery.iter().all(|slice| slice.len() == shard_size));
138
139        decoder.add_original_shard(1, &original[1]).unwrap();
140        decoder.add_recovery_shard(0, recovery[0]).unwrap();
141        decoder.add_recovery_shard(1, recovery[1]).unwrap();
142
143        let result: DecoderResult = decoder.decode().unwrap();
144
145        assert_eq!(result.restored_original(0).unwrap(), original[0]);
146        assert!(result.restored_original(1).is_none());
147        assert_eq!(result.restored_original(2).unwrap(), original[2]);
148        assert!(result.restored_original(3).is_none());
149
150        let mut iter: RestoredOriginal = result.restored_original_iter();
151        assert_eq!(iter.next(), Some((0, original[0].as_slice())));
152        assert_eq!(iter.next(), Some((2, original[2].as_slice())));
153        assert_eq!(iter.next(), None);
154        assert_eq!(iter.next(), None);
155    }
156
157    #[test]
158    // DecoderResult::restored_original
159    // DecoderResult::restored_original_iter
160    // RestoredOriginal
161    fn decoder_result() {
162        simple_roundtrip(1024);
163    }
164
165    #[test]
166    fn shard_size_not_divisible_by_64() {
167        for shard_size in [2, 4, 6, 30, 32, 34, 62, 64, 66, 126, 128, 130] {
168            simple_roundtrip(shard_size);
169        }
170    }
171
172    #[test]
173    fn decoder_result_size_hint() {
174        let shard_size = 64;
175        let original = test_util::generate_original(3, shard_size, 0);
176
177        let mut encoder = ReedSolomonEncoder::new(3, 2, shard_size).unwrap();
178        let mut decoder = ReedSolomonDecoder::new(3, 2, shard_size).unwrap();
179
180        for original in &original {
181            encoder.add_original_shard(original).unwrap();
182        }
183
184        let result = encoder.encode().unwrap();
185        let recovery: Vec<_> = result.recovery_iter().collect();
186
187        decoder.add_original_shard(1, &original[1]).unwrap();
188        decoder.add_recovery_shard(0, recovery[0]).unwrap();
189        decoder.add_recovery_shard(1, recovery[1]).unwrap();
190
191        let result: DecoderResult = decoder.decode().unwrap();
192
193        let mut iter: RestoredOriginal = result.restored_original_iter();
194
195        assert_eq!(iter.len(), 2);
196
197        assert!(iter.next().is_some());
198        assert_eq!(iter.len(), 1);
199
200        assert!(iter.next().is_some());
201        assert_eq!(iter.len(), 0);
202
203        assert!(iter.next().is_none());
204        assert_eq!(iter.len(), 0);
205    }
206
207    #[test]
208    fn decoder_result_size_hint_no_missing() {
209        let shard_size = 64;
210        let original = test_util::generate_original(3, shard_size, 0);
211
212        let mut encoder = ReedSolomonEncoder::new(3, 2, shard_size).unwrap();
213        let mut decoder = ReedSolomonDecoder::new(3, 2, shard_size).unwrap();
214
215        for original in &original {
216            encoder.add_original_shard(original).unwrap();
217        }
218
219        let result = encoder.encode().unwrap();
220        let _recovery: Vec<_> = result.recovery_iter().collect();
221
222        // Add all the original shards
223        decoder.add_original_shard(0, &original[0]).unwrap();
224        decoder.add_original_shard(1, &original[1]).unwrap();
225        decoder.add_original_shard(2, &original[2]).unwrap();
226
227        let result: DecoderResult = decoder.decode().unwrap();
228
229        let mut iter: RestoredOriginal = result.restored_original_iter();
230
231        assert_eq!(iter.len(), 0);
232
233        assert!(iter.next().is_none());
234        assert_eq!(iter.len(), 0);
235
236        assert!(iter.next().is_none());
237        assert_eq!(iter.len(), 0);
238    }
239}