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 vert = size.0 > size.1; let asize = if vert { (size.0 / 2, size.1) } else { (size.0, size.1 / 2) }; let bsize = if vert { (size.0 - size.0 / 2, size.1) } else { (size.0, size.1 - size.1 / 2) }; let a = Block::read(source, asize)?; let b = Block::read(source, bsize)?; [a, b] })), 2 => BlockInner::Reference { translation: (0, 0), //source.get()?, }, x => bail!("corrupt block type ({})", x), }; Ok(Self { size, inner }) } }