Skip to main content

reed_solomon_simd/
encoder_result.rs

1use crate::rate::EncoderWork;
2
3// ======================================================================
4// EncoderResult - PUBLIC
5
6/// Result of encoding. Contains the generated recovery shards.
7///
8/// This struct is created by [`ReedSolomonEncoder::encode`]
9/// and [`RateEncoder::encode`].
10///
11/// [`RateEncoder::encode`]: crate::rate::RateEncoder::encode
12/// [`ReedSolomonEncoder::encode`]: crate::ReedSolomonEncoder::encode
13pub struct EncoderResult<'a> {
14    work: &'a mut EncoderWork,
15}
16
17impl EncoderResult<'_> {
18    /// Returns recovery shard with given `index`
19    /// or `None` if `index >= recovery_count`.
20    ///
21    /// Recovery shards have indexes `0..recovery_count`
22    /// and these same indexes must be used when decoding.
23    pub fn recovery(&self, index: usize) -> Option<&[u8]> {
24        self.work.recovery(index)
25    }
26
27    /// Returns iterator over all recovery shards ordered by their indexes.
28    ///
29    /// Recovery shards have indexes `0..recovery_count`
30    /// and these same indexes must be used when decoding.
31    pub fn recovery_iter(&self) -> Recovery<'_> {
32        Recovery::new(self.work)
33    }
34}
35
36// ======================================================================
37// EncoderResult - CRATE
38
39impl<'a> EncoderResult<'a> {
40    pub(crate) fn new(work: &'a mut EncoderWork) -> Self {
41        Self { work }
42    }
43}
44
45// ======================================================================
46// EncoderResult - IMPL DROP
47
48impl Drop for EncoderResult<'_> {
49    fn drop(&mut self) {
50        self.work.reset_received();
51    }
52}
53
54// ======================================================================
55// Recovery - PUBLIC
56
57/// Iterator over generated recovery shards.
58///
59/// This struct is created by [`EncoderResult::recovery_iter`].
60pub struct Recovery<'a> {
61    ended: bool,
62    next_index: usize,
63    work: &'a EncoderWork,
64}
65
66// ======================================================================
67// Recovery - IMPL Iterator
68
69impl<'a> Iterator for Recovery<'a> {
70    type Item = &'a [u8];
71    fn next(&mut self) -> Option<&'a [u8]> {
72        if self.ended {
73            None
74        } else if let Some(next) = self.work.recovery(self.next_index) {
75            self.next_index += 1;
76            Some(next)
77        } else {
78            self.ended = true;
79            None
80        }
81    }
82
83    fn size_hint(&self) -> (usize, Option<usize>) {
84        let remaining = self.work.recovery_count() - self.next_index;
85        (remaining, Some(remaining))
86    }
87}
88
89// ======================================================================
90// Recovery - IMPL ExactSizeIterator
91
92impl ExactSizeIterator for Recovery<'_> {}
93
94// ======================================================================
95// Recovery - CRATE
96
97impl<'a> Recovery<'a> {
98    pub(crate) fn new(work: &'a EncoderWork) -> Self {
99        Self {
100            ended: false,
101            next_index: 0,
102            work,
103        }
104    }
105}
106
107// ======================================================================
108// TESTS
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113    use crate::{test_util, ReedSolomonEncoder};
114
115    #[cfg(not(feature = "std"))]
116    use alloc::vec::Vec;
117
118    #[test]
119    // EncoderResult::recovery
120    // EncoderResult::recovery_iter
121    // Recovery
122    fn encoder_result() {
123        let original = test_util::generate_original(2, 1024, 123);
124        let mut encoder = ReedSolomonEncoder::new(2, 3, 1024).unwrap();
125
126        for original in &original {
127            encoder.add_original_shard(original).unwrap();
128        }
129
130        let result: EncoderResult = encoder.encode().unwrap();
131
132        let mut all = Vec::new();
133        all.push(result.recovery(0).unwrap());
134        all.push(result.recovery(1).unwrap());
135        all.push(result.recovery(2).unwrap());
136        assert!(result.recovery(3).is_none());
137        test_util::assert_hash(all, test_util::LOW_2_3);
138
139        let mut iter: Recovery = result.recovery_iter();
140        let mut all = Vec::new();
141        all.push(iter.next().unwrap());
142        all.push(iter.next().unwrap());
143        all.push(iter.next().unwrap());
144        assert!(iter.next().is_none());
145        test_util::assert_hash(all, test_util::LOW_2_3);
146    }
147
148    #[test]
149    fn encoder_result_size_hint() {
150        let original = test_util::generate_original(2, 1024, 123);
151        let mut encoder = ReedSolomonEncoder::new(2, 3, 1024).unwrap();
152
153        for original in &original {
154            encoder.add_original_shard(original).unwrap();
155        }
156
157        let result: EncoderResult = encoder.encode().unwrap();
158
159        let mut iter: Recovery = result.recovery_iter();
160
161        assert_eq!(iter.len(), 3);
162
163        assert!(iter.next().is_some());
164        assert!(iter.next().is_some());
165        assert_eq!(iter.len(), 1);
166
167        assert!(iter.next().is_some());
168        assert_eq!(iter.len(), 0);
169
170        assert!(iter.next().is_none());
171        assert_eq!(iter.len(), 0);
172    }
173}