pub use self::{
decoder_result::{DecoderResult, Originals, Recoveries, RecoveryDecoderResult},
encoder_result::{EncoderResult, Recovery},
engine::SHARD_CHUNK_BYTES,
wrappers::{Decoder, Encoder},
};
use thiserror::Error;
#[cfg(test)]
#[macro_use]
mod test_util;
mod decoder_result;
mod encoder_result;
mod wrappers;
pub mod algorithm {
#![doc = include_str!("algorithm.md")]
}
pub mod engine;
pub mod rate;
#[derive(Clone, Copy, Debug, Error, PartialEq)]
pub enum Error {
#[error("different shard size: expected {shard_bytes} bytes, got {got} bytes")]
DifferentShardSize {
shard_bytes: usize,
got: usize,
},
#[error("duplicate original shard index: {index}")]
DuplicateOriginalShardIndex {
index: usize,
},
#[error("duplicate recovery shard index: {index}")]
DuplicateRecoveryShardIndex {
index: usize,
},
#[error("invalid original shard index: {index} >= original_count {original_count}")]
InvalidOriginalShardIndex {
original_count: usize,
index: usize,
},
#[error("invalid recovery shard index: {index} >= recovery_count {recovery_count}")]
InvalidRecoveryShardIndex {
recovery_count: usize,
index: usize,
},
#[error("invalid shard size: {shard_bytes} bytes (must non-zero and multiple of 2)")]
InvalidShardSize {
shard_bytes: usize,
},
#[error(
"not enough shards: {original_received_count} original + {recovery_received_count} recovery < {original_count} original_count"
)]
NotEnoughShards {
original_count: usize,
original_received_count: usize,
recovery_received_count: usize,
},
#[error(
"too few original shards: got {original_received_count} shards while original_count is {original_count}"
)]
TooFewOriginalShards {
original_count: usize,
original_received_count: usize,
},
#[error("too many original shards: got more than original_count ({original_count}) shards")]
TooManyOriginalShards {
original_count: usize,
},
#[error(
"unsupported shard count: {original_count} original shards with {recovery_count} recovery shards"
)]
UnsupportedShardCount {
original_count: usize,
recovery_count: usize,
},
}
#[cfg(test)]
mod tests {
use super::*;
use crate::reed_solomon::{engine::DefaultEngine, rate::DefaultRate};
#[test]
fn roundtrip() {
let original = test_util::generate_original(2, 1024, 123);
let mut encoder = Encoder::new(2, 3, 1024).unwrap();
for shard in &original {
encoder.add_original_shard(shard).unwrap();
}
let encoding = encoder.encode().unwrap();
let recovery: Vec<_> = encoding.recovery_iter().map(<[u8]>::to_vec).collect();
test_util::assert_hash(&recovery, test_util::LOW_2_3);
let mut decoder = Decoder::new(2, 3, 1024).unwrap();
decoder.add_recovery_shard(0, &recovery[0]).unwrap();
decoder.add_recovery_shard(1, &recovery[1]).unwrap();
let decoding = decoder.decode().unwrap().unwrap();
let mut restored = decoding.original_iter();
assert_eq!(restored.next(), Some((0, original[0].as_slice())));
assert_eq!(restored.next(), Some((1, original[1].as_slice())));
assert_eq!(restored.next(), None);
}
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<Encoder>();
assert_send::<Decoder>();
assert_send::<DefaultEngine>();
assert_send::<DefaultRate<DefaultEngine>>();
assert_send::<DecoderResult<'_>>();
assert_send::<RecoveryDecoderResult<'_>>();
assert_send::<EncoderResult<'_>>();
assert_send::<Error>();
}
#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Encoder>();
assert_sync::<Decoder>();
assert_sync::<DefaultEngine>();
assert_sync::<DefaultRate<DefaultEngine>>();
assert_sync::<DecoderResult<'_>>();
assert_sync::<RecoveryDecoderResult<'_>>();
assert_sync::<EncoderResult<'_>>();
assert_sync::<Error>();
}
}