commonware_cryptography/reed_solomon/rate/
decoder_work.rs1use crate::reed_solomon::{
2 engine::{Shards, ShardsRefMut, SHARD_CHUNK_BYTES},
3 Error,
4};
5use fixedbitset::FixedBitSet;
6
7pub struct DecoderWork {
14 original_count: usize,
15 recovery_count: usize,
16 shard_bytes: usize,
17
18 original_base_pos: usize,
19 recovery_base_pos: usize,
20
21 original_received_count: usize,
22 recovery_received_count: usize,
23 received: FixedBitSet,
25 shards: Shards,
26}
27
28impl DecoderWork {
29 pub const fn new() -> Self {
32 Self {
33 original_count: 0,
34 recovery_count: 0,
35 shard_bytes: 0,
36
37 original_base_pos: 0,
38 recovery_base_pos: 0,
39
40 original_received_count: 0,
41 recovery_received_count: 0,
42 received: FixedBitSet::new(),
43 shards: Shards::new(),
44 }
45 }
46}
47
48impl Default for DecoderWork {
52 fn default() -> Self {
53 Self::new()
54 }
55}
56
57impl DecoderWork {
61 pub(crate) fn add_original_shard<T: AsRef<[u8]>>(
62 &mut self,
63 index: usize,
64 original_shard: T,
65 ) -> Result<(), Error> {
66 let pos = self.original_base_pos + index;
67 let original_shard = original_shard.as_ref();
68
69 if index >= self.original_count {
70 Err(Error::InvalidOriginalShardIndex {
71 original_count: self.original_count,
72 index,
73 })
74 } else if self.received[pos] {
75 Err(Error::DuplicateOriginalShardIndex { index })
76 } else if original_shard.len() != self.shard_bytes {
77 Err(Error::DifferentShardSize {
78 shard_bytes: self.shard_bytes,
79 got: original_shard.len(),
80 })
81 } else {
82 self.shards.insert(pos, original_shard);
83
84 self.original_received_count += 1;
85 self.received.set(pos, true);
86 Ok(())
87 }
88 }
89
90 pub(crate) fn add_recovery_shard<T: AsRef<[u8]>>(
91 &mut self,
92 index: usize,
93 recovery_shard: T,
94 ) -> Result<(), Error> {
95 let pos = self.recovery_base_pos + index;
96 let recovery_shard = recovery_shard.as_ref();
97
98 if index >= self.recovery_count {
99 Err(Error::InvalidRecoveryShardIndex {
100 recovery_count: self.recovery_count,
101 index,
102 })
103 } else if self.received[pos] {
104 Err(Error::DuplicateRecoveryShardIndex { index })
105 } else if recovery_shard.len() != self.shard_bytes {
106 Err(Error::DifferentShardSize {
107 shard_bytes: self.shard_bytes,
108 got: recovery_shard.len(),
109 })
110 } else {
111 self.shards.insert(pos, recovery_shard);
112
113 self.recovery_received_count += 1;
114 self.received.set(pos, true);
115 Ok(())
116 }
117 }
118
119 pub(crate) fn decode_begin(
122 &mut self,
123 ) -> Result<Option<(ShardsRefMut<'_>, usize, usize, &FixedBitSet)>, Error> {
124 if self.original_received_count + self.recovery_received_count < self.original_count {
125 Err(Error::NotEnoughShards {
126 original_count: self.original_count,
127 original_received_count: self.original_received_count,
128 recovery_received_count: self.recovery_received_count,
129 })
130 } else if self.original_received_count == self.original_count {
131 Ok(None)
132 } else {
133 Ok(Some((
134 self.shards.as_ref_mut(),
135 self.original_count,
136 self.recovery_count,
137 &self.received,
138 )))
139 }
140 }
141
142 pub(crate) const fn original_count(&self) -> usize {
143 self.original_count
144 }
145
146 pub(crate) fn reset(
147 &mut self,
148 original_count: usize,
149 recovery_count: usize,
150 shard_bytes: usize,
151
152 original_base_pos: usize,
153 recovery_base_pos: usize,
154 work_count: usize,
155 ) {
156 assert!(shard_bytes.is_multiple_of(2));
157
158 self.original_count = original_count;
159 self.recovery_count = recovery_count;
160 self.shard_bytes = shard_bytes;
161
162 self.original_base_pos = original_base_pos;
163 self.recovery_base_pos = recovery_base_pos;
164
165 self.original_received_count = 0;
166 self.recovery_received_count = 0;
167
168 let max_received_pos = core::cmp::max(
169 original_base_pos + original_count,
170 recovery_base_pos + recovery_count,
171 );
172
173 self.received.clear();
174 if self.received.len() < max_received_pos {
175 self.received.grow(max_received_pos);
176 }
177
178 self.shards
179 .resize(work_count, shard_bytes.div_ceil(SHARD_CHUNK_BYTES));
180 }
181
182 pub(crate) fn reset_received(&mut self) {
183 self.original_received_count = 0;
184 self.recovery_received_count = 0;
185 self.received.clear();
186 }
187
188 pub(crate) fn original(&self, index: usize) -> Option<&[u8]> {
190 let pos = self.original_base_pos + index;
191
192 if index < self.original_count && !self.received[pos] {
193 Some(&self.shards[pos].as_flattened()[..self.shard_bytes])
194 } else {
195 None
196 }
197 }
198
199 pub(crate) fn recovery(&self, index: usize) -> Option<&[u8]> {
204 let pos = self.recovery_base_pos + index;
205
206 if self.missing_original_count() > 0 && index < self.recovery_count && !self.received[pos] {
207 Some(&self.shards[pos].as_flattened()[..self.shard_bytes])
208 } else {
209 None
210 }
211 }
212
213 pub(crate) fn undo_last_chunk_encoding(&mut self) {
214 self.shards.undo_last_chunk_encoding(
215 self.shard_bytes,
216 self.original_base_pos..self.original_base_pos + self.original_count,
217 );
218 }
219
220 pub(crate) fn undo_last_chunk_encoding_recovery(&mut self) {
221 self.shards.undo_last_chunk_encoding(
222 self.shard_bytes,
223 self.recovery_base_pos..self.recovery_base_pos + self.recovery_count,
224 );
225 }
226
227 pub(crate) const fn missing_original_count(&self) -> usize {
228 self.original_count - self.original_received_count
229 }
230
231 pub(crate) const fn recovery_count(&self) -> usize {
232 self.recovery_count
233 }
234
235 pub(crate) const fn missing_recovery_count(&self) -> usize {
236 self.recovery_count - self.recovery_received_count
237 }
238}