Skip to main content

ordpath/
writer.rs

1use std::io::Write;
2
3use crate::enc::Encoding;
4use crate::{Error, ErrorKind};
5
6/// The `Writer` struct allows reading ORDPATH encoded values directly from any source implementing [`Write`].
7pub struct Writer<W: Write + ?Sized, E: Encoding> {
8    acc: u64,
9    len: u8,
10    enc: E,
11    dst: W,
12}
13
14impl<W: Write, E: Encoding> Writer<W, E> {
15    /// Creates a new `Writer` for the givev destination.
16    pub fn new(dst: W, enc: E) -> Self {
17        Self {
18            acc: 0,
19            len: 0,
20            enc,
21            dst,
22        }
23    }
24
25    /// Write a value into this writer.
26    pub fn write(&mut self, value: i64) -> Result<(), Error> {
27        let stage = self
28            .enc
29            .stage_by_value(value)
30            .ok_or_else(|| Error::new(ErrorKind::InvalidInput))?;
31        let prefix = stage.prefix() as u64;
32        let value = (value - stage.ordinal_min()) as u64;
33
34        let buf = match stage.bits() < 64 {
35            true => ((prefix << stage.ordinal_bits()) | value) << (64 - stage.bits()),
36            false => (prefix << (64 - stage.prefix_bits())) | (value >> (stage.bits() - 64)),
37        };
38
39        let len = self.len & 127;
40        self.acc |= buf >> len;
41
42        let len = len + stage.bits();
43        self.len = 128
44            | if len < 64 {
45                len
46            } else {
47                let left = len - 64;
48
49                self.len = 0;
50                self.dst.write_all(&self.acc.to_be_bytes())?;
51                self.acc = if stage.bits() <= 64 {
52                    buf << (stage.bits() - left)
53                } else {
54                    value << (stage.bits() - left)
55                };
56
57                left
58            };
59
60        Ok(())
61    }
62}
63
64impl<W: Write + ?Sized, E: Encoding> Drop for Writer<W, E> {
65    fn drop(&mut self) {
66        if self.len > 0 {
67            let len = (self.len as usize & 127).div_ceil(8);
68            let acc = &self.acc.to_be_bytes()[..len];
69
70            _ = self.dst.write_all(acc);
71        }
72    }
73}