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#[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 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 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 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 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 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 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}