use anyhow::bail; use crate::{ pixel::Pixel, ser::{Ser, Sink, Source}, }; #[derive(Clone, Debug)] pub struct Block { pub size: (usize, usize), pub inner: BlockInner, } #[derive(Clone, Debug)] pub enum BlockInner { Literal(Vec), Split(Box<[Block; 2]>), Reference { translation: (usize, usize) }, } impl Block { pub fn write(&self, sink: &mut impl std::io::Write) -> anyhow::Result<()> { match &self.inner { BlockInner::Literal(pixels) => { sink.put(0u8)?; pixels.write(sink)?; } BlockInner::Split(box [a, b]) => { sink.put(1u8)?; a.write(sink)?; b.write(sink)?; } BlockInner::Reference { translation } => { sink.put(2u8)?; // sink.put(*translation)?; } } Ok(()) } pub fn read(source: &mut impl std::io::Read, size: (usize, usize)) -> anyhow::Result { let inner = match source.get::()? { 0 => BlockInner::Literal(source.get()?), 1 => BlockInner::Split(Box::new({ let subsize_left = if size.0 > size.1 { (size.0 / 2, size.1) } else { (size.0, size.1 / 2) }; let subsize_right = (size.0 - subsize_left.0, size.1 - subsize_left.1); let a = Block::read(source, subsize_left)?; let b = Block::read(source, subsize_right)?; [a, b] })), 2 => BlockInner::Reference { translation: (0, 0), //source.get()?, }, x => bail!("corrupt block type ({})", x), }; Ok(Self { size, inner }) } }