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
use anyhow::{anyhow, ensure, Result};

pub mod schema;

pub struct Writer<'b, I> {
    iter: I,
    static_size: usize,
    has_trailer: bool,
    bytes: &'b mut [u8],
}

impl<'b, I> Writer<'b, I> {
    pub fn new(iter: I, static_size: usize, has_trailer: bool, bytes: &'b mut [u8]) -> Self {
        Self {
            iter,
            static_size,
            has_trailer,
            bytes,
        }
    }
}

impl<'a, 'b, I, F> Writer<'b, I>
where
    I: Iterator<Item = &'a F>,
    F: structpack::SizedField + 'static,
{
    pub fn write(&mut self, value: F::Value<'_>) -> Result<()> {
        let field = self
            .iter
            .next()
            .ok_or_else(|| anyhow!("all fields have been written"))?;
        field.write(self.bytes, value)?;
        Ok(())
    }

    fn verify_completion(&mut self) -> Result<()> {
        ensure!(
            self.iter.next().is_none(),
            "some parameters have not been written yet"
        );
        Ok(())
    }

    /// Returns total (static + trailer) len
    pub fn write_trailer_and_finish(mut self, trailer: &[u8]) -> Result<usize> {
        ensure!(
            self.has_trailer,
            "this command has no trailer(RAW) parameter"
        );
        self.verify_completion()?;
        let buf = self
            .bytes
            .get_mut(self.static_size..self.static_size + trailer.len())
            .ok_or_else(|| anyhow!("trailer is too long for the buffer"))?;
        buf.copy_from_slice(trailer);
        Ok(self.static_size + trailer.len())
    }

    pub fn finish(mut self) -> Result<usize> {
        self.verify_completion()?;
        Ok(self.static_size)
    }
}