1use crate::asm::{opcode::ParseOp, ToBytes, ToOpcode, TryFromBytes};
4
5#[derive(Clone, Debug, PartialEq)]
20pub struct BytecodeMapped<Op, Bytes = Vec<u8>> {
21    bytecode: Bytes,
23    op_indices: Vec<usize>,
27    _op_ty: core::marker::PhantomData<Op>,
29}
30
31#[derive(Clone, Copy, Debug, PartialEq)]
33pub struct BytecodeMappedSlice<'a, Op> {
34    bytecode: &'a [u8],
36    op_indices: &'a [usize],
38    _op_ty: core::marker::PhantomData<Op>,
40}
41
42pub struct BytecodeMappedLazy<Op, I> {
45    pub(crate) mapped: BytecodeMapped<Op>,
47    pub(crate) iter: I,
49}
50
51impl<Op> BytecodeMapped<Op, Vec<u8>> {
52    pub fn push_op(&mut self, op: Op)
54    where
55        Op: ToBytes,
56    {
57        self.op_indices.push(self.bytecode.len());
58        self.bytecode.extend(op.to_bytes());
59    }
60}
61
62impl<Op, Bytes> BytecodeMapped<Op, Bytes>
63where
64    Bytes: core::ops::Deref<Target = [u8]>,
65{
66    pub fn try_from_bytes(bytes: Bytes) -> Result<BytecodeMapped<Op, Bytes>, Op::Error>
71    where
72        Op: ToOpcode + TryFromBytes,
73        Op::Opcode: ParseOp<Op = Op> + TryFrom<u8>,
74        Op::Error: From<<Op::Opcode as TryFrom<u8>>::Error> + From<<Op::Opcode as ParseOp>::Error>,
75    {
76        let bytecode = bytes.deref();
77        let mut op_indices = Vec::with_capacity(bytecode.len() / std::mem::size_of::<Op>());
78        let mut iter_enum = bytecode.iter().enumerate();
79        while let Some((ix, &opcode_byte)) = iter_enum.next() {
80            let opcode = Op::Opcode::try_from(opcode_byte)?;
81            let mut op_bytes = iter_enum.by_ref().map(|(_, &byte)| byte);
82            let _op = opcode.parse_op(&mut op_bytes)?;
83            op_indices.push(ix);
84        }
85        Ok(BytecodeMapped {
86            bytecode: bytes,
87            op_indices,
88            _op_ty: core::marker::PhantomData,
89        })
90    }
91
92    pub fn as_slice(&self) -> BytecodeMappedSlice<Op> {
94        BytecodeMappedSlice {
95            bytecode: self.bytecode(),
96            op_indices: self.op_indices(),
97            _op_ty: self._op_ty,
98        }
99    }
100
101    pub fn bytecode(&self) -> &[u8] {
103        self.bytecode.deref()
104    }
105
106    pub fn ops_from(&self, start: usize) -> Option<BytecodeMappedSlice<Op>> {
112        Some(BytecodeMappedSlice {
113            bytecode: self.bytecode(),
114            op_indices: self.op_indices.get(start..)?,
115            _op_ty: self._op_ty,
116        })
117    }
118
119    pub fn op(&self, ix: usize) -> Option<Op>
121    where
122        Op: TryFromBytes,
123    {
124        let slice = self.ops_from(ix)?;
125        slice.ops().next()
126    }
127
128    pub fn ops(&self) -> impl '_ + Iterator<Item = Op>
130    where
131        Op: TryFromBytes,
132    {
133        expect_ops_from_indices(self.bytecode(), self.op_indices.iter().copied())
134    }
135}
136
137impl<Op, Bytes> BytecodeMapped<Op, Bytes> {
138    pub fn op_indices(&self) -> &[usize] {
140        &self.op_indices
141    }
142}
143
144impl<'a, Op> BytecodeMappedSlice<'a, Op> {
145    pub fn op_indices(self) -> &'a [usize] {
147        self.op_indices
148    }
149
150    pub fn ops(self) -> impl 'a + Iterator<Item = Op>
152    where
153        Op: TryFromBytes,
154    {
155        expect_ops_from_indices(self.bytecode, self.op_indices.iter().copied())
156    }
157}
158
159impl<Op, I> BytecodeMappedLazy<Op, I> {
160    pub fn new<J>(bytes: J) -> Self
162    where
163        J: IntoIterator<IntoIter = I>,
164        I: Iterator<Item = u8>,
165    {
166        let iter = bytes.into_iter();
167        let (min, _) = iter.size_hint();
168        let mapped = BytecodeMapped {
169            bytecode: Vec::with_capacity(min),
170            op_indices: Vec::with_capacity(min),
171            _op_ty: core::marker::PhantomData,
172        };
173        Self { mapped, iter }
174    }
175}
176
177impl<Op> Default for BytecodeMapped<Op> {
180    fn default() -> Self {
181        BytecodeMapped {
182            bytecode: Default::default(),
183            op_indices: Default::default(),
184            _op_ty: Default::default(),
185        }
186    }
187}
188
189impl<Op> FromIterator<Op> for BytecodeMapped<Op>
191where
192    Op: ToBytes,
193{
194    fn from_iter<T: IntoIterator<Item = Op>>(iter: T) -> Self {
195        let iter = iter.into_iter();
196        let (min, _) = iter.size_hint();
197        let mut mapped = BytecodeMapped {
198            bytecode: Vec::with_capacity(min),
199            op_indices: Vec::with_capacity(min),
200            _op_ty: core::marker::PhantomData,
201        };
202        iter.for_each(|op| mapped.push_op(op));
203        mapped
204    }
205}
206
207impl<Op> TryFrom<Vec<u8>> for BytecodeMapped<Op>
209where
210    Op: ToOpcode + TryFromBytes,
211    Op::Opcode: ParseOp<Op = Op> + TryFrom<u8>,
212    Op::Error: From<<Op::Opcode as TryFrom<u8>>::Error> + From<<Op::Opcode as ParseOp>::Error>,
213{
214    type Error = Op::Error;
215    fn try_from(bytecode: Vec<u8>) -> Result<Self, Self::Error> {
216        Self::try_from_bytes(bytecode)
217    }
218}
219
220impl<'a, Op> TryFrom<&'a [u8]> for BytecodeMapped<Op, &'a [u8]>
222where
223    Op: ToOpcode + TryFromBytes,
224    Op::Opcode: ParseOp<Op = Op> + TryFrom<u8>,
225    Op::Error: From<<Op::Opcode as TryFrom<u8>>::Error> + From<<Op::Opcode as ParseOp>::Error>,
226{
227    type Error = Op::Error;
228    fn try_from(bytecode: &'a [u8]) -> Result<Self, Self::Error> {
229        Self::try_from_bytes(bytecode)
230    }
231}
232
233fn expect_ops_from_indices<'a, Op>(
236    bytecode: &'a [u8],
237    op_indices: impl 'a + IntoIterator<Item = usize>,
238) -> impl 'a + Iterator<Item = Op>
239where
240    Op: TryFromBytes,
241{
242    const EXPECT_MSG: &str = "validated upon construction";
243    op_indices.into_iter().map(|ix| {
244        let mut bytes = bytecode[ix..].iter().copied();
245        Op::try_from_bytes(&mut bytes)
246            .expect(EXPECT_MSG)
247            .expect(EXPECT_MSG)
248    })
249}