swf_emitter/
io_bits.rs

1use std::cmp::min;
2use std::io;
3
4pub trait WriteBits {
5  fn align(&mut self) -> io::Result<()>;
6
7  fn write_bool_bits(&mut self, value: bool) -> io::Result<()>;
8
9  fn write_i32_bits(&mut self, bits: u32, value: i32) -> io::Result<()>;
10
11  fn write_u32_bits(&mut self, bits: u32, value: u32) -> io::Result<()>;
12
13  /// Align the writer and return a byte writer
14  fn write_bytes(&mut self) -> io::Result<&mut dyn io::Write>;
15}
16
17pub struct BitsWriter<W: io::Write> {
18  bit: u32,
19  buffer: u8,
20  inner: W,
21}
22
23impl<W: io::Write> BitsWriter<W> {
24  pub fn new(inner: W) -> BitsWriter<W> {
25    BitsWriter {
26      bit: 0,
27      buffer: 0,
28      inner,
29    }
30  }
31
32  pub fn into_inner(mut self) -> io::Result<W> {
33    self.align()?;
34    Ok(self.inner)
35  }
36}
37
38impl<W: io::Write> WriteBits for BitsWriter<W> {
39  fn align(&mut self) -> io::Result<()> {
40    if self.bit != 0 {
41      self.inner.write_all(&[self.buffer])?;
42      self.bit = 0;
43      self.buffer = 0;
44    }
45    Ok(())
46  }
47
48  fn write_bool_bits(&mut self, value: bool) -> io::Result<()> {
49    debug_assert!(self.bit < 8);
50
51    if value {
52      self.buffer |= 1 << (7 - self.bit);
53    }
54    self.bit += 1;
55
56    if self.bit == 8 {
57      self.inner.write_all(&[self.buffer])?;
58      self.bit = 0;
59      self.buffer = 0;
60    }
61
62    Ok(())
63  }
64
65  fn write_i32_bits(&mut self, bits: u32, value: i32) -> io::Result<()> {
66    // TODO: Add debug assertions to check the range of `value`
67    if value < 0 {
68      self.write_u32_bits(bits, ((1 << bits) + value) as u32)
69    } else {
70      self.write_u32_bits(bits, value as u32)
71    }
72  }
73
74  fn write_u32_bits(&mut self, mut bits: u32, value: u32) -> io::Result<()> {
75    // TODO: Add debug assertions to check the range of `value`
76    debug_assert!(bits <= 32);
77    debug_assert!(self.bit < 8);
78
79    while bits > 0 {
80      let available_bits = 8 - self.bit;
81      let consumed_bits = min(available_bits, bits);
82      debug_assert!((1..=8).contains(&consumed_bits));
83
84      let chunk: u8 = ((value >> (bits - consumed_bits)) & ((1 << consumed_bits) - 1)) as u8;
85      self.buffer |= chunk << (available_bits - consumed_bits);
86      bits -= consumed_bits;
87      self.bit += consumed_bits;
88
89      if self.bit == 8 {
90        self.inner.write_all(&[self.buffer])?;
91        self.bit = 0;
92        self.buffer = 0;
93      }
94    }
95
96    Ok(())
97  }
98
99  fn write_bytes(&mut self) -> io::Result<&mut dyn io::Write> {
100    self.align()?;
101    Ok(&mut self.inner)
102  }
103}