use crate::reed_solomon::rate::EncoderWork;
pub struct EncoderResult<'a> {
work: &'a mut EncoderWork,
}
impl EncoderResult<'_> {
pub fn recovery(&self, index: usize) -> Option<&[u8]> {
self.work.recovery(index)
}
pub const fn recovery_iter(&self) -> Recovery<'_> {
Recovery::new(self.work)
}
}
impl<'a> EncoderResult<'a> {
pub(crate) const fn new(work: &'a mut EncoderWork) -> Self {
Self { work }
}
}
impl Drop for EncoderResult<'_> {
fn drop(&mut self) {
self.work.reset_received();
}
}
pub struct Recovery<'a> {
ended: bool,
next_index: usize,
work: &'a EncoderWork,
}
impl<'a> Iterator for Recovery<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<&'a [u8]> {
if self.ended {
None
} else if let Some(next) = self.work.recovery(self.next_index) {
self.next_index += 1;
Some(next)
} else {
self.ended = true;
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.work.recovery_count() - self.next_index;
(remaining, Some(remaining))
}
}
impl ExactSizeIterator for Recovery<'_> {}
impl<'a> Recovery<'a> {
pub(crate) const fn new(work: &'a EncoderWork) -> Self {
Self {
ended: false,
next_index: 0,
work,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::reed_solomon::{test_util, Encoder};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[test]
fn encoder_result() {
let original = test_util::generate_original(2, 1024, 123);
let mut encoder = Encoder::new(2, 3, 1024).unwrap();
for original in &original {
encoder.add_original_shard(original).unwrap();
}
let result: EncoderResult<'_> = encoder.encode().unwrap();
let all = vec![
result.recovery(0).unwrap(),
result.recovery(1).unwrap(),
result.recovery(2).unwrap(),
];
assert!(result.recovery(3).is_none());
test_util::assert_hash(all, test_util::LOW_2_3);
let mut iter: Recovery<'_> = result.recovery_iter();
let all = vec![
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
];
assert!(iter.next().is_none());
test_util::assert_hash(all, test_util::LOW_2_3);
}
#[test]
fn encoder_result_size_hint() {
let original = test_util::generate_original(2, 1024, 123);
let mut encoder = Encoder::new(2, 3, 1024).unwrap();
for original in &original {
encoder.add_original_shard(original).unwrap();
}
let result: EncoderResult<'_> = encoder.encode().unwrap();
let mut iter: Recovery<'_> = result.recovery_iter();
assert_eq!(iter.len(), 3);
assert!(iter.next().is_some());
assert!(iter.next().is_some());
assert_eq!(iter.len(), 1);
assert!(iter.next().is_some());
assert_eq!(iter.len(), 0);
assert!(iter.next().is_none());
assert_eq!(iter.len(), 0);
}
}