aboutsummaryrefslogtreecommitdiff
path: root/bv1/codec/src/serialize.rs
blob: 86b29195979190397b195bf9b26b1f442ad0c172 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use crate::{split::split, Block, Pixel, Ref, View, P2};
use std::io::{Read, Result, 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::new(Block::read(r, av)?),
                    Box::new(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)
}