dusk_cdf/
encoder.rs

1mod context;
2
3#[cfg(test)]
4mod tests;
5
6use std::borrow::Borrow;
7use std::fs::{File, OpenOptions};
8use std::io::{self, Seek, Write};
9use std::path::Path;
10
11pub use context::{EncoderContext, EncoderContextFileProvider, EncoderContextProvider};
12
13use crate::{Config, EncodableConstraint, EncodableElement, EncodableWitness, Preamble};
14
15/// An encoder for CDF format
16#[derive(Debug)]
17pub struct Encoder<WI, CI, T> {
18    context: EncoderContext,
19    witnesses: WI,
20    constraints: CI,
21    target: T,
22}
23
24impl<WI, CI, T> Encoder<WI, CI, T>
25where
26    WI: ExactSizeIterator,
27    CI: ExactSizeIterator,
28{
29    pub(crate) fn with_preamble(
30        preamble: Preamble,
31        witnesses: WI,
32        constraints: CI,
33        target: T,
34    ) -> Self {
35        let context = EncoderContext::from_preamble(preamble);
36
37        Self {
38            context,
39            witnesses,
40            constraints,
41            target,
42        }
43    }
44
45    /// Create a new encoder
46    pub(crate) fn new(config: Config, witnesses: WI, constraints: CI, target: T) -> Self {
47        let preamble = Preamble::new(witnesses.len(), constraints.len(), config);
48
49        Self::with_preamble(preamble, witnesses, constraints, target)
50    }
51
52    /// Return the underlying encoder
53    pub fn into_inner(self) -> T {
54        self.target
55    }
56}
57
58impl<WI, CI> Encoder<WI, CI, File>
59where
60    WI: ExactSizeIterator,
61    CI: ExactSizeIterator,
62{
63    /// Initialize the encoder, filling a file with required bytes.
64    ///
65    /// Check [`File::set_len`]
66    pub fn init_file<P>(config: Config, witnesses: WI, constraints: CI, path: P) -> io::Result<Self>
67    where
68        P: AsRef<Path>,
69    {
70        let file = OpenOptions::new().write(true).create(true).open(path)?;
71
72        let slf = Self::new(config, witnesses, constraints, file);
73        let len = slf.context.preamble().source_cache_offset();
74
75        slf.target.set_len(len as u64)?;
76
77        Ok(slf)
78    }
79}
80
81impl<WI, CI, B> Encoder<WI, CI, io::BufWriter<B>>
82where
83    WI: ExactSizeIterator,
84    CI: ExactSizeIterator,
85    B: io::Write + io::Seek,
86{
87    /// Initialize the encoder, filling the buffer with required bytes.
88    pub fn init_buffer(
89        config: Config,
90        witnesses: WI,
91        constraints: CI,
92        buffer: B,
93    ) -> io::Result<Self> {
94        let buffer = io::BufWriter::new(buffer);
95        let mut slf = Self::new(config, witnesses, constraints, buffer);
96        let len = slf.context.preamble().source_cache_offset();
97
98        let n = slf
99            .target
100            .rewind()
101            .and_then(|_| slf.target.write(&vec![0u8; len]))?;
102
103        if n != len {
104            return Err(io::Error::new(
105                io::ErrorKind::Other,
106                format!(
107                    "the target wrote {} bytes instead of the expected {}!",
108                    n, len
109                ),
110            ));
111        }
112
113        Ok(slf)
114    }
115}
116
117impl<WI, CI> Encoder<WI, CI, io::Cursor<Vec<u8>>>
118where
119    WI: ExactSizeIterator,
120    CI: ExactSizeIterator,
121{
122    /// Initialize the encoder, filling the buffer with required bytes.
123    pub fn init_cursor(config: Config, witnesses: WI, constraints: CI) -> Self {
124        let preamble = Preamble::new(witnesses.len(), constraints.len(), config);
125        let len = preamble.source_cache_offset();
126        let bytes = vec![0u8; len];
127        let cursor = io::Cursor::new(bytes);
128
129        Self::with_preamble(preamble, witnesses, constraints, cursor)
130    }
131}
132
133impl<W, WI, C, CI, T> Encoder<WI, CI, T>
134where
135    W: Borrow<EncodableWitness>,
136    WI: Iterator<Item = W> + ExactSizeIterator,
137    C: Borrow<EncodableConstraint>,
138    CI: Iterator<Item = C> + ExactSizeIterator,
139    T: io::Write + io::Seek,
140{
141    /// Write all witnesses and constraints into the target
142    pub fn write_all<P>(&mut self, provider: P) -> io::Result<usize>
143    where
144        P: EncoderContextProvider,
145    {
146        let Self {
147            context,
148            witnesses,
149            constraints,
150            target,
151        } = self;
152
153        let preamble = *context.preamble();
154        let n = preamble.try_to_writer(target.by_ref(), context)?;
155
156        let n = witnesses.try_fold(n, |n, w| {
157            w.borrow()
158                .try_to_writer(target.by_ref(), context)
159                .map(|x| n + x)
160        })?;
161
162        let n = constraints.try_fold(n, |n, c| {
163            c.borrow()
164                .try_to_writer(target.by_ref(), context)
165                .map(|x| n + x)
166        })?;
167
168        let n = n + self.context.write_all(target, provider)?;
169
170        Ok(n)
171    }
172}