diff options
Diffstat (limited to 'lvc/src/serialize.rs')
-rw-r--r-- | lvc/src/serialize.rs | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/lvc/src/serialize.rs b/lvc/src/serialize.rs new file mode 100644 index 0000000..ac6230e --- /dev/null +++ b/lvc/src/serialize.rs @@ -0,0 +1,123 @@ +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<Pixel> { + 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<Pixel> { + 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<P2> { + 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<Block> { + 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<u8> { + 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<i16> { + Ok((read_byte(r)? as u16 | ((read_byte(r)? as u16) << 8)) as i16) +} |