use crate::split::split; use crate::Block; use crate::Pixel; use crate::Ref; use crate::View; use crate::P2; use std::io::Read; use std::io::Result; use std::io::Write; impl Pixel { #[inline] pub fn write(&self, w: &mut impl Write) -> Result<()> { w.write_all(&[ self.r.clamp(0, 255) as u8, self.g.clamp(0, 255) as u8, self.b.clamp(0, 255) as u8, ]) } #[inline] pub fn read(r: &mut impl Read) -> Result { Ok(Self { r: read_byte(r)? as i16, g: read_byte(r)? as i16, b: read_byte(r)? as i16, }) } } impl Pixel { #[inline] pub fn write_full(&self, w: &mut impl Write) -> Result<()> { write_word(w, self.r)?; write_word(w, self.g)?; write_word(w, self.b)?; Ok(()) } #[inline] pub fn read_full(r: &mut impl Read) -> Result { Ok(Self { r: read_word(r)?, g: read_word(r)?, b: read_word(r)?, }) } } impl P2 { #[inline] pub fn write(&self, w: &mut impl Write) -> Result<()> { write_word(w, self.x as i16)?; write_word(w, self.y as i16)?; Ok(()) } #[inline] pub fn read(r: &mut impl Read) -> Result { Ok(Self { x: read_word(r)? as i32, y: read_word(r)? as i32, }) } } impl Block { pub fn write(&self, w: &mut impl Write) -> Result<()> { match self { Block::Split(a, b) => { w.write_all(&[0])?; a.write(w)?; b.write(w)?; } Block::Lit(pixels) => { w.write_all(&[1])?; for p in pixels { p.write(w)?; } } Block::Ref(k) => { w.write_all(&[2])?; k.pos_off.write(w)?; k.color_off.write_full(w)?; } } Ok(()) } pub fn read(r: &mut impl Read, view: View) -> Result { match read_byte(r)? { 0 => { let [av, bv] = split(view); Ok(Block::Split( box Block::read(r, av)?, box Block::read(r, bv)?, )) } 1 => { let mut px = vec![]; for _ in 0..view.size().area() { px.push(Pixel::read(r)?) } Ok(Block::Lit(px)) } 2 => Ok(Block::Ref(Ref { pos_off: P2::read(r)?, color_off: Pixel::read_full(r)?, })), _ => Err(std::io::Error::other("unknown block variant")), } } } #[inline] fn read_byte(r: &mut impl Read) -> Result { let mut buf = [0u8]; r.read_exact(&mut buf)?; Ok(buf[0]) } #[inline] fn write_word(w: &mut impl Write, v: i16) -> Result<()> { w.write_all(&[(v & 0xff) as u8, (v >> 8) as u8]) } #[inline] fn read_word(r: &mut impl Read) -> Result { Ok((read_byte(r)? as u16 | ((read_byte(r)? as u16) << 8)) as i16) }