use std::convert::TryFrom;
use raptorq::ObjectTransmissionInformation;
use super::{encoder::MAX_MTU, TRANSMISSION_INFO_SIZE};
fn int_div_ceil(num: u64, denom: u64) -> u32 {
if num % denom == 0 {
(num / denom) as u32
} else {
(num / denom + 1) as u32
}
}
const MAX_SOURCE_SYMBOLS_PER_BLOCK: u32 = 56403;
#[derive(Debug, Clone)]
pub(crate) struct SafeObjectTransmissionInformation {
pub inner: ObjectTransmissionInformation,
pub max_blocks: usize,
}
#[derive(Debug, Clone)]
pub enum TransmissionInformationError {
SourceBlocksZero,
SymbolSizeZero,
SymbolSizeGreaterThanMTU,
SymbolSizeNotAligned,
TransferLengthZero,
TransferLengthExceeded,
TooManySourceSymbols,
}
impl TryFrom<&[u8; TRANSMISSION_INFO_SIZE]>
for SafeObjectTransmissionInformation
{
type Error = TransmissionInformationError;
fn try_from(
value: &[u8; TRANSMISSION_INFO_SIZE],
) -> Result<Self, Self::Error> {
let config = ObjectTransmissionInformation::deserialize(value);
if config.source_blocks() == 0 {
return Err(TransmissionInformationError::SourceBlocksZero);
}
if config.symbol_size() == 0 {
return Err(TransmissionInformationError::SymbolSizeZero);
}
if config.transfer_length() == 0 {
return Err(TransmissionInformationError::TransferLengthZero);
}
if config.symbol_size() > MAX_MTU {
return Err(TransmissionInformationError::SymbolSizeGreaterThanMTU);
}
if config.symbol_alignment() != 8 {
return Err(TransmissionInformationError::SymbolSizeNotAligned);
}
let kt =
int_div_ceil(config.transfer_length(), config.symbol_size() as u64);
let (kl, _, zl, zs) = raptorq::partition(kt, config.source_blocks());
let block_length = u64::from(kl) * u64::from(config.symbol_size());
let source_block_symbols =
int_div_ceil(block_length, config.symbol_size() as u64);
match source_block_symbols <= MAX_SOURCE_SYMBOLS_PER_BLOCK {
true => Ok(SafeObjectTransmissionInformation {
inner: config,
max_blocks: (zl + zs) as usize,
}),
false => Err(TransmissionInformationError::TooManySourceSymbols),
}
}
}