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}