reed_solomon_16/rate/
decoder_work.rs1use fixedbitset::FixedBitSet;
2
3use crate::{
4 engine::{Shards, ShardsRefMut},
5 Error,
6};
7
8pub struct DecoderWork {
15 original_count: usize,
16 recovery_count: usize,
17 shard_bytes: usize,
18
19 original_base_pos: usize,
20 recovery_base_pos: usize,
21
22 original_received_count: usize,
23 recovery_received_count: usize,
24 received: FixedBitSet,
26 shards: Shards,
27}
28
29impl DecoderWork {
30 pub fn new() -> Self {
33 Self {
34 original_count: 0,
35 recovery_count: 0,
36 shard_bytes: 0,
37
38 original_base_pos: 0,
39 recovery_base_pos: 0,
40
41 original_received_count: 0,
42 recovery_received_count: 0,
43 received: FixedBitSet::new(),
44 shards: Shards::new(),
45 }
46 }
47}
48
49impl Default for DecoderWork {
53 fn default() -> Self {
54 Self::new()
55 }
56}
57
58impl DecoderWork {
62 pub(crate) fn add_original_shard<T: AsRef<[u8]>>(
63 &mut self,
64 index: usize,
65 original_shard: T,
66 ) -> Result<(), Error> {
67 let pos = self.original_base_pos + index;
68 let original_shard = original_shard.as_ref();
69
70 if index >= self.original_count {
71 Err(Error::InvalidOriginalShardIndex {
72 original_count: self.original_count,
73 index,
74 })
75 } else if self.received[pos] {
76 Err(Error::DuplicateOriginalShardIndex { index })
77 } else if original_shard.len() != self.shard_bytes {
78 Err(Error::DifferentShardSize {
79 shard_bytes: self.shard_bytes,
80 got: original_shard.len(),
81 })
82 } else {
83 self.shards[pos].copy_from_slice(original_shard);
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[pos].copy_from_slice(recovery_shard);
112 self.recovery_received_count += 1;
113 self.received.set(pos, true);
114 Ok(())
115 }
116 }
117
118 pub(crate) fn decode_begin(
121 &mut self,
122 ) -> Result<Option<(ShardsRefMut, usize, usize, &FixedBitSet)>, Error> {
123 if self.original_received_count + self.recovery_received_count < self.original_count {
124 Err(Error::NotEnoughShards {
125 original_count: self.original_count,
126 original_received_count: self.original_received_count,
127 recovery_received_count: self.recovery_received_count,
128 })
129 } else if self.original_received_count == self.original_count {
130 Ok(None)
131 } else {
132 Ok(Some((
133 self.shards.as_ref_mut(),
134 self.original_count,
135 self.recovery_count,
136 &self.received,
137 )))
138 }
139 }
140
141 pub(crate) fn original_count(&self) -> usize {
142 self.original_count
143 }
144
145 pub(crate) fn reset(
146 &mut self,
147 original_count: usize,
148 recovery_count: usize,
149 shard_bytes: usize,
150
151 original_base_pos: usize,
152 recovery_base_pos: usize,
153 work_count: usize,
154 ) {
155 self.original_count = original_count;
156 self.recovery_count = recovery_count;
157 self.shard_bytes = shard_bytes;
158
159 self.original_base_pos = original_base_pos;
160 self.recovery_base_pos = recovery_base_pos;
161
162 self.original_received_count = 0;
163 self.recovery_received_count = 0;
164
165 let max_received_pos = std::cmp::max(
166 original_base_pos + original_count,
167 recovery_base_pos + recovery_count,
168 );
169
170 self.received.clear();
171 if self.received.len() < max_received_pos {
172 self.received.grow(max_received_pos);
173 }
174
175 self.shards.resize(work_count, shard_bytes);
176 }
177
178 pub(crate) fn reset_received(&mut self) {
179 self.original_received_count = 0;
180 self.recovery_received_count = 0;
181 self.received.clear();
182 }
183
184 pub(crate) fn restored_original(&self, index: usize) -> Option<&[u8]> {
186 let pos = self.original_base_pos + index;
187
188 if index < self.original_count && !self.received[pos] {
189 Some(&self.shards[pos])
190 } else {
191 None
192 }
193 }
194}