rustfs_erasure_codec/core/shard_by_shard.rs
1use crate::Field;
2use crate::errors::{Error, SBSError};
3
4use super::ReedSolomon;
5
6/// Bookkeeper for shard by shard encoding.
7///
8/// This is useful for avoiding incorrect use of
9/// `encode_single` and `encode_single_sep`
10///
11/// # Use cases
12///
13/// Shard by shard encoding is useful for streamed data encoding
14/// where you do not have all the needed data shards immediately,
15/// but you want to spread out the encoding workload rather than
16/// doing the encoding after everything is ready.
17///
18/// A concrete example would be network packets encoding,
19/// where encoding packet by packet as you receive them may be more efficient
20/// than waiting for N packets then encode them all at once.
21///
22/// # Example
23///
24/// ```
25/// # #[macro_use] extern crate rustfs_erasure_codec;
26/// # use rustfs_erasure_codec::*;
27/// # fn main () {
28/// use rustfs_erasure_codec::galois_8::Field;
29/// let r: ReedSolomon<Field> = ReedSolomon::new(3, 2).unwrap();
30///
31/// let mut sbs = ShardByShard::new(&r);
32///
33/// let mut shards = shards!([0u8, 1, 2, 3, 4],
34/// [5, 6, 7, 8, 9],
35/// // say we don't have the 3rd data shard yet
36/// // and we want to fill it in later
37/// [0, 0, 0, 0, 0],
38/// [0, 0, 0, 0, 0],
39/// [0, 0, 0, 0, 0]);
40///
41/// // encode 1st and 2nd data shard
42/// sbs.encode(&mut shards).unwrap();
43/// sbs.encode(&mut shards).unwrap();
44///
45/// // fill in 3rd data shard
46/// shards[2][0] = 10.into();
47/// shards[2][1] = 11.into();
48/// shards[2][2] = 12.into();
49/// shards[2][3] = 13.into();
50/// shards[2][4] = 14.into();
51///
52/// // now do the encoding
53/// sbs.encode(&mut shards).unwrap();
54///
55/// assert!(r.verify(&shards).unwrap());
56/// # }
57/// ```
58#[derive(PartialEq, Debug)]
59pub struct ShardByShard<'a, F: 'a + Field> {
60 codec: &'a ReedSolomon<F>,
61 cur_input: usize,
62}
63
64impl<'a, F: 'a + Field> ShardByShard<'a, F> {
65 /// Create a new shard-by-shard encoder.
66 pub fn new(codec: &'a ReedSolomon<F>) -> ShardByShard<'a, F> {
67 ShardByShard {
68 codec,
69 cur_input: 0,
70 }
71 }
72
73 /// Returns `true` if all data shards have been encoded and parity is ready.
74 pub fn parity_ready(&self) -> bool {
75 self.cur_input == self.codec.data_shard_count
76 }
77
78 /// Reset to accept a new batch of data shards.
79 ///
80 /// Returns [`SBSError::LeftoverShards`] if the previous batch was incomplete.
81 pub fn reset(&mut self) -> Result<(), SBSError> {
82 if self.cur_input > 0 && !self.parity_ready() {
83 return Err(SBSError::LeftoverShards);
84 }
85
86 self.cur_input = 0;
87
88 Ok(())
89 }
90
91 /// Force-reset without checking for leftover shards.
92 pub fn reset_force(&mut self) {
93 self.cur_input = 0;
94 }
95
96 /// Returns the index of the next data shard expected.
97 pub fn cur_input_index(&self) -> usize {
98 self.cur_input
99 }
100
101 fn return_ok_and_incre_cur_input(&mut self) -> Result<(), SBSError> {
102 self.cur_input += 1;
103 Ok(())
104 }
105
106 fn sbs_encode_checks<U: AsRef<[F::Elem]> + AsMut<[F::Elem]>>(
107 &mut self,
108 slices: &mut [U],
109 ) -> Result<(), SBSError> {
110 let internal_checks = |codec: &ReedSolomon<F>, data: &mut [U]| -> Result<(), Error> {
111 check_piece_count!(all => codec, data);
112 check_slices!(multi => data);
113
114 Ok(())
115 };
116
117 if self.parity_ready() {
118 return Err(SBSError::TooManyCalls);
119 }
120
121 match internal_checks(self.codec, slices) {
122 Ok(()) => Ok(()),
123 Err(e) => Err(SBSError::RSError(e)),
124 }
125 }
126
127 fn sbs_encode_sep_checks<T: AsRef<[F::Elem]>, U: AsRef<[F::Elem]> + AsMut<[F::Elem]>>(
128 &mut self,
129 data: &[T],
130 parity: &mut [U],
131 ) -> Result<(), SBSError> {
132 let internal_checks =
133 |codec: &ReedSolomon<F>, data: &[T], parity: &mut [U]| -> Result<(), Error> {
134 check_piece_count!(data => codec, data);
135 check_piece_count!(parity => codec, parity);
136 check_slices!(multi => data, multi => parity);
137
138 Ok(())
139 };
140
141 if self.parity_ready() {
142 return Err(SBSError::TooManyCalls);
143 }
144
145 match internal_checks(self.codec, data, parity) {
146 Ok(()) => Ok(()),
147 Err(e) => Err(SBSError::RSError(e)),
148 }
149 }
150
151 /// Encode the next data shard in the batch.
152 pub fn encode<T, U>(&mut self, mut shards: T) -> Result<(), SBSError>
153 where
154 T: AsRef<[U]> + AsMut<[U]>,
155 U: AsRef<[F::Elem]> + AsMut<[F::Elem]>,
156 {
157 let shards = shards.as_mut();
158 self.sbs_encode_checks(shards)?;
159
160 self.codec
161 .encode_single(self.cur_input, shards)
162 .map_err(SBSError::RSError)?;
163
164 self.return_ok_and_incre_cur_input()
165 }
166
167 /// Encode the next data shard using separate data and parity slices.
168 pub fn encode_sep<T: AsRef<[F::Elem]>, U: AsRef<[F::Elem]> + AsMut<[F::Elem]>>(
169 &mut self,
170 data: &[T],
171 parity: &mut [U],
172 ) -> Result<(), SBSError> {
173 self.sbs_encode_sep_checks(data, parity)?;
174
175 self.codec
176 .encode_single_sep(self.cur_input, data[self.cur_input].as_ref(), parity)
177 .map_err(SBSError::RSError)?;
178
179 self.return_ok_and_incre_cur_input()
180 }
181}