essential_constraint_vm/
bytecode.rs1use 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}