1use std::convert::Infallible;
2use std::convert::TryFrom;
3use std::io;
4
5pub trait WriterBackend {
6 type Error;
7 fn extend_from_slice(&mut self, data: &[u8]) -> Result<(), Self::Error>;
8}
9
10/// `io::Write` generates bloated code (with backtrace for every byte written),
11/// so small boxes are written infallibly.
12impl WriterBackend for Vec<u8> {
13 type Error = Infallible;
14 #[inline(always)]
15 fn extend_from_slice(&mut self, data: &[u8]) -> Result<(), Infallible> {
16 self.extend_from_slice(data);
17 Ok(())
18 }
19}
20
21pub struct IO<W>(pub W);
22
23impl<W: io::Write> WriterBackend for IO<W> {
24 type Error = io::Error;
25 #[inline(always)]
26 fn extend_from_slice(&mut self, data: &[u8]) -> io::Result<()> {
27 self.0.write_all(buf:data)
28 }
29}
30
31pub struct Writer<'p, 'w, B> {
32 parent: Option<&'p mut usize>,
33 left: Option<usize>,
34 out: &'w mut B,
35}
36
37impl<'w, B> Writer<'static, 'w, B> {
38 #[inline]
39 pub fn new(out: &'w mut B) -> Self {
40 Self {
41 parent: None,
42 left: None,
43 out,
44 }
45 }
46}
47
48impl<'p, 'w, B: WriterBackend> Writer<'p, 'w, B> {
49 #[inline]
50 pub fn new_box(&mut self, len: usize) -> Writer<'_, '_, B> {
51 Writer {
52 parent: match &mut self.left {
53 Some(l) => Some(l),
54 None => None,
55 },
56 left: Some(len),
57 out: self.out,
58 }
59 }
60
61 #[inline(always)]
62 pub fn full_box(&mut self, typ: [u8; 4], version: u8) -> Result<(), B::Error> {
63 self.basic_box(typ)?;
64 self.push(&[version, 0, 0, 0])
65 }
66
67 #[inline]
68 pub fn basic_box(&mut self, typ: [u8; 4]) -> Result<(), B::Error> {
69 let len = self.left.unwrap();
70 if let Some(parent) = &mut self.parent {
71 **parent -= len;
72 }
73 match u32::try_from(len) {
74 Ok(len) => self.u32(len)?,
75 Err(_) => {
76 self.u32(1)?;
77 self.u64(len as u64)?;
78 }
79 }
80 self.push(&typ)
81 }
82
83 #[inline(always)]
84 pub fn push(&mut self, data: &[u8]) -> Result<(), B::Error> {
85 *self.left.as_mut().unwrap() -= data.len();
86 self.out.extend_from_slice(data)
87 }
88
89 #[inline(always)]
90 pub fn u8(&mut self, val: u8) -> Result<(), B::Error> {
91 self.push(std::slice::from_ref(&val))
92 }
93
94 #[inline(always)]
95 pub fn u16(&mut self, val: u16) -> Result<(), B::Error> {
96 self.push(&val.to_be_bytes())
97 }
98
99 #[inline(always)]
100 pub fn u32(&mut self, val: u32) -> Result<(), B::Error> {
101 self.push(&val.to_be_bytes())
102 }
103
104 #[inline(always)]
105 pub fn u64(&mut self, val: u64) -> Result<(), B::Error> {
106 self.push(&val.to_be_bytes())
107 }
108}
109
110#[cfg(debug_assertions)]
111impl<B> Drop for Writer<'_, '_, B> {
112 fn drop(&mut self) {
113 if let Some(unwritten_bytes) = self.left {
114 assert_eq!(0, unwritten_bytes);
115 }
116 }
117}
118