use std::convert::From;
use std::fmt::{Debug, Display, Formatter};
#[derive(Copy, Clone, Eq, Ord, Hash, PartialOrd, PartialEq)]
pub struct BlockInfo(pub u32);
impl BlockInfo {
const MORE_FLAG: u32 = 0b1000;
pub const NUM_MAX: u32 = ((1 << 20) - 1);
const SZX_RESERVED: u8 = 0b0111;
pub const SZX_MAX: u8 = Self::SZX_RESERVED - 1;
pub fn new(num: u32, m: bool, szx: u8) -> Option<BlockInfo> {
if num > Self::NUM_MAX || szx > Self::SZX_MAX {
None
} else {
Some(BlockInfo((num << 4) + ((m as u32) << 3) + szx as u32))
}
}
#[inline]
pub fn num(&self) -> u32 {
self.0 >> 4
}
#[inline]
pub fn more_flag(&self) -> bool {
(self.0 & Self::MORE_FLAG) == Self::MORE_FLAG
}
#[inline]
pub fn szx(&self) -> u8 {
self.0 as u8 & 0b111
}
#[inline]
pub fn offset(&self) -> usize {
let val = self.0 as usize;
(val & !0xF) << (val & 0b0111)
}
#[inline]
pub fn len(&self) -> usize {
1 << (self.szx() as usize + 4)
}
pub fn is_max_block(&self) -> bool {
self.num() == Self::NUM_MAX
}
pub fn is_invalid(&self) -> bool {
(self.num() > Self::NUM_MAX) || self.szx() == Self::SZX_RESERVED
}
pub fn valid(self) -> Option<BlockInfo> {
if self.is_invalid() {
None
} else {
Some(self)
}
}
pub fn next(&self) -> Option<BlockInfo> {
if self.num() < Self::NUM_MAX {
BlockInfo(self.0 + 0x10).valid()
} else {
None
}
}
pub fn smaller(&self) -> Option<BlockInfo> {
let szx = self.szx();
if szx != Self::SZX_RESERVED && szx > 0 {
Self::new(self.num() * 2, self.more_flag(), szx - 1)
} else {
None
}
}
pub fn with_more_flag(&self) -> BlockInfo {
BlockInfo(self.0 | Self::MORE_FLAG)
}
pub fn without_more_flag(&self) -> BlockInfo {
BlockInfo(self.0 & !Self::MORE_FLAG)
}
}
impl From<u32> for BlockInfo {
fn from(x: u32) -> Self {
BlockInfo(x)
}
}
impl Default for BlockInfo {
fn default() -> Self {
BlockInfo(6)
}
}
impl Display for BlockInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
"{}/{}/{}",
self.num(),
self.more_flag() as u8,
self.len()
)?;
if self.is_invalid() {
f.write_str("(!)")
} else {
Ok(())
}
}
}
impl Debug for BlockInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "BlockInfo(0x{:06X})", self.0)?;
Display::fmt(self, f)?;
f.write_str(")")
}
}
#[derive(Debug)]
pub struct BlockReconstructor<F> {
next_block: BlockInfo,
is_finished: bool,
write: F,
}
impl<F: Default + std::io::Write> Default for BlockReconstructor<F> {
fn default() -> Self {
BlockReconstructor::new(F::default(), Default::default())
}
}
impl<F> BlockReconstructor<F>
where
F: std::io::Write,
{
pub fn new(write: F, next_block: BlockInfo) -> BlockReconstructor<F> {
BlockReconstructor {
next_block: next_block.without_more_flag(),
is_finished: false,
write,
}
}
pub fn next_block(&self) -> BlockInfo {
self.next_block
}
pub fn is_finished(&self) -> bool {
self.is_finished
}
pub fn into_inner(self) -> F {
self.write
}
pub fn feed(&mut self, block: BlockInfo, payload: &[u8]) -> Result<bool, ()> {
if self.is_finished {
return Ok(true);
}
if block.offset() < self.next_block.offset() {
return Ok(false);
}
if block.offset() > self.next_block.offset() {
return Err(());
}
if !block.more_flag() {
self.is_finished = true;
} else if block.len() > payload.len() {
return Err(());
} else if block.len() < payload.len() {
return Err(());
} else if let Some(next_block) = block.without_more_flag().next() {
self.next_block = next_block;
} else {
return Err(());
}
self.write.write_all(payload).map_err(|_| ())?;
Ok(self.is_finished)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults() {
let block = BlockInfo::default();
assert_eq!(false, block.more_flag());
assert_eq!(6, block.szx());
assert_eq!(0, block.num());
assert_eq!(1024, block.len());
assert_eq!(0, block.offset());
assert_eq!(false, block.is_max_block());
assert_eq!(false, block.is_invalid());
}
#[test]
fn next() {
let block = BlockInfo::default().next().unwrap();
assert_eq!(BlockInfo::default().more_flag(), block.more_flag());
assert_eq!(6, block.szx());
assert_eq!(1, block.num());
assert_eq!(1024, block.len());
assert_eq!(1024, block.offset());
assert_eq!(false, block.is_max_block());
assert_eq!(false, block.is_invalid());
}
#[test]
fn smaller() {
let block = BlockInfo::default().smaller().unwrap();
assert_eq!(BlockInfo::default().more_flag(), block.more_flag());
assert_eq!(5, block.szx());
assert_eq!(0, block.num());
assert_eq!(512, block.len());
assert_eq!(0, block.offset());
assert_eq!(false, block.is_max_block());
assert_eq!(false, block.is_invalid());
}
#[test]
fn next_smaller() {
let block = BlockInfo::default().next().unwrap().smaller().unwrap();
assert_eq!(BlockInfo::default().more_flag(), block.more_flag());
assert_eq!(5, block.szx());
assert_eq!(2, block.num());
assert_eq!(512, block.len());
assert_eq!(1024, block.offset());
assert_eq!(false, block.is_max_block());
assert_eq!(false, block.is_invalid());
let smaller = block.smaller().unwrap();
assert_eq!(256, smaller.len());
assert_eq!(block.offset(), smaller.offset());
}
#[test]
fn with_and_without_more_flag() {
let block = BlockInfo::default().without_more_flag();
assert_eq!(false, block.more_flag());
assert_eq!(6, block.szx());
assert_eq!(0, block.num());
assert_eq!(1024, block.len());
assert_eq!(0, block.offset());
assert_eq!(false, block.is_max_block());
assert_eq!(false, block.is_invalid());
let block = block.with_more_flag();
assert_eq!(true, block.more_flag());
assert_eq!(6, block.szx());
assert_eq!(0, block.num());
assert_eq!(1024, block.len());
assert_eq!(0, block.offset());
assert_eq!(false, block.is_max_block());
assert_eq!(false, block.is_invalid());
}
#[test]
fn check_next() {
let block = BlockInfo::new(BlockInfo::NUM_MAX - 1, true, 6).unwrap();
assert_eq!(true, block.more_flag());
assert_eq!(6, block.szx());
assert_eq!(BlockInfo::NUM_MAX - 1, block.num());
assert_eq!(1024, block.len());
assert_eq!(1073739776, block.offset());
assert_eq!(false, block.is_max_block());
assert_eq!(false, block.is_invalid());
let block = block.next().unwrap();
assert_eq!(true, block.more_flag());
assert_eq!(6, block.szx());
assert_eq!(BlockInfo::NUM_MAX, block.num());
assert_eq!(1024, block.len());
assert_eq!(1073739776 + 1024, block.offset());
assert_eq!(true, block.is_max_block());
assert_eq!(false, block.is_invalid());
assert_eq!(None, block.next());
}
#[test]
fn check_smaller() {
let block = BlockInfo::new(BlockInfo::NUM_MAX - 1, true, 6).unwrap();
assert_eq!(false, block.is_invalid());
assert_eq!(None, block.smaller());
let block = BlockInfo(0);
assert_eq!(false, block.is_invalid());
assert_eq!(None, block.smaller());
}
#[test]
fn validity() {
let block = BlockInfo(0);
assert_eq!(false, block.is_invalid());
assert_eq!(false, block.smaller().is_some());
assert_eq!(true, block.next().is_some());
assert_eq!(Some(block), block.valid());
let block = BlockInfo(1);
assert_eq!(false, block.is_invalid());
assert_eq!(true, block.smaller().is_some());
assert_eq!(true, block.next().is_some());
assert_eq!(Some(block), block.valid());
let block = BlockInfo(!0);
assert_eq!(true, block.is_invalid());
assert_eq!(None, block.smaller());
assert_eq!(None, block.next());
assert_eq!(None, block.valid());
let block = BlockInfo(BlockInfo::SZX_RESERVED as u32);
assert_eq!(true, block.is_invalid());
assert_eq!(None, block.smaller());
assert_eq!(None, block.next());
assert_eq!(None, block.valid());
let block = BlockInfo(BlockInfo::SZX_RESERVED as u32);
assert_eq!(true, block.is_invalid());
assert_eq!(None, block.smaller());
assert_eq!(None, block.next());
assert_eq!(None, block.valid());
}
}