1use crate::lib::std::{
3 fmt,
4 io::{self, Seek as _, SeekFrom, Write},
5};
6
7pub type GenResult<W> = Result<WriteContext<W>, GenError>;
12
13#[derive(Debug)]
15pub enum GenError {
16 BufferTooSmall(usize),
18 BufferTooBig(usize),
20 InvalidOffset,
22 IoError(io::Error),
24
25 CustomError(u32),
27 NotYetImplemented,
29}
30
31impl fmt::Display for GenError {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 write!(f, "{:?}", self)
34 }
35}
36
37#[cfg(feature = "std")]
38impl std::error::Error for GenError {}
39
40impl From<io::Error> for GenError {
41 fn from(err: io::Error) -> Self {
42 GenError::IoError(err)
43 }
44}
45
46pub trait SerializeFn<W>: Fn(WriteContext<W>) -> GenResult<W> {}
53
54impl<W, F: Fn(WriteContext<W>) -> GenResult<W>> SerializeFn<W> for F {}
55
56pub struct WriteContext<W> {
60 pub write: W,
61 pub position: u64,
62}
63
64impl<W: Write> From<W> for WriteContext<W> {
65 fn from(write: W) -> Self {
66 Self { write, position: 0 }
67 }
68}
69
70impl<W: Write> WriteContext<W> {
71 pub fn into_inner(self) -> (W, u64) {
73 (self.write, self.position)
74 }
75}
76
77impl<W: Write> Write for WriteContext<W> {
78 fn write(&mut self, data: &[u8]) -> crate::lib::std::io::Result<usize> {
79 let amt = self.write.write(data)?;
80 self.position += amt as u64;
81 Ok(amt)
82 }
83
84 #[cfg(feature = "std")]
85 fn flush(&mut self) -> io::Result<()> {
86 self.write.flush()
87 }
88}
89
90impl<W: Seek> io::Seek for WriteContext<W> {
91 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
92 let old_pos = self.write.stream_position()?;
93 let new_pos = self.write.seek(pos)?;
94 if new_pos >= old_pos {
95 self.position += new_pos - old_pos;
96 } else {
97 self.position -= old_pos - new_pos;
98 }
99 Ok(new_pos)
100 }
101}
102
103pub fn gen<W: Write, F: SerializeFn<W>>(f: F, w: W) -> Result<(W, u64), GenError> {
121 f(WriteContext::from(w)).map(|ctx| ctx.into_inner())
122}
123
124pub fn gen_simple<W: Write, F: SerializeFn<W>>(f: F, w: W) -> Result<W, GenError> {
141 f(WriteContext::from(w)).map(|ctx| ctx.into_inner().0)
142}
143
144pub trait Skip: Write {
146 fn skip(s: WriteContext<Self>, sz: usize) -> GenResult<Self>
147 where
148 Self: Sized;
149}
150
151pub trait BackToTheBuffer: Write {
154 fn reserve_write_use<
155 Tmp,
156 Gen: Fn(WriteContext<Self>) -> Result<(WriteContext<Self>, Tmp), GenError>,
157 Before: Fn(WriteContext<Self>, Tmp) -> GenResult<Self>,
158 >(
159 s: WriteContext<Self>,
160 reserved: usize,
161 gen: &Gen,
162 before: &Before,
163 ) -> Result<WriteContext<Self>, GenError>
164 where
165 Self: Sized;
166}
167
168pub trait Seek: Write + io::Seek {}
170impl Seek for io::Cursor<&mut [u8]> {}
171
172impl<W: Seek> BackToTheBuffer for W {
173 fn reserve_write_use<
174 Tmp,
175 Gen: Fn(WriteContext<Self>) -> Result<(WriteContext<Self>, Tmp), GenError>,
176 Before: Fn(WriteContext<Self>, Tmp) -> GenResult<Self>,
177 >(
178 mut s: WriteContext<Self>,
179 reserved: usize,
180 gen: &Gen,
181 before: &Before,
182 ) -> Result<WriteContext<Self>, GenError> {
183 let start = s.stream_position()?;
184 let begin = s.seek(SeekFrom::Current(reserved as i64))?;
185 let (mut buf, tmp) = gen(s)?;
186 let end = buf.stream_position()?;
187 buf.seek(SeekFrom::Start(start))?;
188 let mut buf = before(buf, tmp)?;
189 let pos = buf.stream_position()?;
190 if pos != begin {
191 return Err(GenError::BufferTooBig((begin - pos) as usize));
192 }
193 buf.seek(SeekFrom::Start(end))?;
194 Ok(buf)
195 }
196}
197
198impl Skip for &mut [u8] {
199 fn skip(s: WriteContext<Self>, len: usize) -> Result<WriteContext<Self>, GenError> {
200 if s.write.len() < len {
201 Err(GenError::BufferTooSmall(len - s.write.len()))
202 } else {
203 Ok(WriteContext {
204 write: &mut s.write[len..],
205 position: s.position + len as u64,
206 })
207 }
208 }
209}
210
211impl Skip for io::Cursor<&mut [u8]> {
212 fn skip(mut s: WriteContext<Self>, len: usize) -> GenResult<Self> {
213 let remaining = s
214 .write
215 .get_ref()
216 .len()
217 .saturating_sub(s.write.position() as usize);
218 if remaining < len {
219 Err(GenError::BufferTooSmall(len - remaining))
220 } else {
221 let cursor_position = s.write.position();
222 s.write.set_position(cursor_position + len as u64);
223 s.position += len as u64;
224 Ok(s)
225 }
226 }
227}
228
229impl BackToTheBuffer for &mut [u8] {
230 fn reserve_write_use<
231 Tmp,
232 Gen: Fn(WriteContext<Self>) -> Result<(WriteContext<Self>, Tmp), GenError>,
233 Before: Fn(WriteContext<Self>, Tmp) -> GenResult<Self>,
234 >(
235 s: WriteContext<Self>,
236 reserved: usize,
237 gen: &Gen,
238 before: &Before,
239 ) -> Result<WriteContext<Self>, GenError> {
240 let WriteContext {
241 write: slice,
242 position: original_position,
243 } = s;
244
245 let (res, buf) = slice.split_at_mut(reserved);
246 let (new_context, tmp) = gen(WriteContext {
247 write: buf,
248 position: original_position + reserved as u64,
249 })?;
250
251 let res = before(
252 WriteContext {
253 write: res,
254 position: original_position,
255 },
256 tmp,
257 )?;
258
259 if !res.write.is_empty() {
260 return Err(GenError::BufferTooBig(res.write.len()));
261 }
262
263 Ok(new_context)
264 }
265}
266
267#[cfg(feature = "std")]
268impl BackToTheBuffer for Vec<u8> {
269 fn reserve_write_use<
270 Tmp,
271 Gen: Fn(WriteContext<Self>) -> Result<(WriteContext<Self>, Tmp), GenError>,
272 Before: Fn(WriteContext<Self>, Tmp) -> GenResult<Self>,
273 >(
274 s: WriteContext<Self>,
275 reserved: usize,
276 gen: &Gen,
277 before: &Before,
278 ) -> Result<WriteContext<Self>, GenError> {
279 let WriteContext {
280 write: mut vec,
281 position: original_position,
282 } = s;
283
284 let start_len = vec.len();
285 vec.extend(std::iter::repeat(0).take(reserved));
286
287 let (mut new_context, tmp) = gen(WriteContext {
288 write: vec,
289 position: original_position + reserved as u64,
290 })?;
291
292 let tmp_context = before(
293 WriteContext {
294 write: Vec::new(),
295 position: original_position,
296 },
297 tmp,
298 )?;
299
300 let tmp_written = tmp_context.write.len();
301 if tmp_written != reserved {
302 return Err(GenError::BufferTooBig(reserved - tmp_written));
303 }
304
305 new_context.write[start_len..(start_len + reserved)]
309 .copy_from_slice(&tmp_context.write[..]);
310
311 Ok(new_context)
312 }
313}