1use std::{array::from_fn, borrow::Borrow, marker::PhantomData};
2
3use openvm_circuit_primitives::{ColumnsAir, StructReflection, StructReflectionHelper};
4use openvm_circuit_primitives_derive::AlignedBorrow;
5use openvm_cpu_backend::CpuBackend;
6use openvm_instructions::{instruction::Instruction, LocalOpcode};
7use openvm_stark_backend::{
8 p3_air::{Air, AirBuilder, BaseAir},
9 p3_field::PrimeCharacteristicRing,
10 p3_matrix::{dense::RowMajorMatrix, Matrix},
11 p3_maybe_rayon::prelude::*,
12 prover::AirProvingContext,
13 BaseAirWithPublicValues, PartitionedBaseAir, StarkProtocolConfig, Val,
14};
15use serde::{Deserialize, Serialize};
16
17use crate::{
18 arch::RowMajorMatrixArena,
19 primitives::Chip,
20 system::memory::{online::TracingMemory, MemoryAuxColsFactory, SharedMemoryHelper},
21};
22
23pub trait VmAdapterInterface<T> {
25 type Reads;
27 type Writes;
29 type ProcessedInstruction;
34}
35
36pub trait VmAdapterAir<AB: AirBuilder>: BaseAir<AB::F> {
37 type Interface: VmAdapterInterface<AB::Expr>;
38
39 fn eval(
46 &self,
47 builder: &mut AB,
48 local: &[AB::Var],
49 interface: AdapterAirContext<AB::Expr, Self::Interface>,
50 );
51
52 fn get_from_pc(&self, local: &[AB::Var]) -> AB::Var;
54}
55
56pub trait VmCoreAir<AB, I>: BaseAirWithPublicValues<AB::F>
57where
58 AB: AirBuilder,
59 I: VmAdapterInterface<AB::Expr>,
60{
61 fn eval(
63 &self,
64 builder: &mut AB,
65 local_core: &[AB::Var],
66 from_pc: AB::Var,
67 ) -> AdapterAirContext<AB::Expr, I>;
68
69 fn start_offset(&self) -> usize;
73
74 fn start_offset_expr(&self) -> AB::Expr {
75 AB::Expr::from_usize(self.start_offset())
76 }
77
78 fn expr_to_global_expr(&self, local_expr: impl Into<AB::Expr>) -> AB::Expr {
79 self.start_offset_expr() + local_expr.into()
80 }
81
82 fn opcode_to_global_expr(&self, local_opcode: impl LocalOpcode) -> AB::Expr {
83 self.expr_to_global_expr(AB::Expr::from_usize(local_opcode.local_usize()))
84 }
85}
86
87pub struct AdapterAirContext<T, I: VmAdapterInterface<T>> {
88 pub to_pc: Option<T>,
90 pub reads: I::Reads,
91 pub writes: I::Writes,
92 pub instruction: I::ProcessedInstruction,
93}
94
95pub trait TraceFiller<F>: Send + Sync {
97 fn fill_trace(
101 &self,
102 mem_helper: &MemoryAuxColsFactory<F>,
103 trace: &mut RowMajorMatrix<F>,
104 rows_used: usize,
105 ) where
106 F: Send + Sync + Clone,
107 {
108 let width = trace.width();
109 trace.values[..rows_used * width]
110 .par_chunks_exact_mut(width)
111 .for_each(|row_slice| {
112 self.fill_trace_row(mem_helper, row_slice);
113 });
114 trace.values[rows_used * width..]
115 .par_chunks_exact_mut(width)
116 .for_each(|row_slice| {
117 self.fill_dummy_trace_row(row_slice);
118 });
119 }
120
121 fn fill_trace_row(&self, _mem_helper: &MemoryAuxColsFactory<F>, _row_slice: &mut [F]) {
129 unreachable!("fill_trace_row is not implemented")
130 }
131
132 fn fill_dummy_trace_row(&self, _row_slice: &mut [F]) {
137 }
139
140 fn generate_public_values(&self) -> Vec<F> {
142 vec![]
143 }
144}
145
146#[derive(derive_new::new)]
150pub struct VmChipWrapper<F, FILLER> {
151 pub inner: FILLER,
152 pub mem_helper: SharedMemoryHelper<F>,
153}
154
155impl<SC, FILLER, RA> Chip<RA, CpuBackend<SC>> for VmChipWrapper<Val<SC>, FILLER>
156where
157 SC: StarkProtocolConfig,
158 FILLER: TraceFiller<Val<SC>>,
159 RA: RowMajorMatrixArena<Val<SC>>,
160{
161 fn generate_proving_ctx(&self, arena: RA) -> AirProvingContext<CpuBackend<SC>> {
162 let rows_used = arena.trace_offset() / arena.width();
163 let mut trace = arena.into_matrix();
164 let mem_helper = self.mem_helper.as_borrowed();
165 self.inner.fill_trace(&mem_helper, &mut trace, rows_used);
166
167 AirProvingContext::simple(trace, self.inner.generate_public_values())
168 }
169}
170
171pub trait AdapterTraceExecutor<F>: Clone {
178 const WIDTH: usize;
179 type ReadData;
180 type WriteData;
181 type RecordMut<'a>
185 where
186 Self: 'a;
187
188 fn start(pc: u32, memory: &TracingMemory, record: &mut Self::RecordMut<'_>);
189
190 fn read(
191 &self,
192 memory: &mut TracingMemory,
193 instruction: &Instruction<F>,
194 record: &mut Self::RecordMut<'_>,
195 ) -> Self::ReadData;
196
197 fn write(
198 &self,
199 memory: &mut TracingMemory,
200 instruction: &Instruction<F>,
201 data: Self::WriteData,
202 record: &mut Self::RecordMut<'_>,
203 );
204}
205
206pub trait AdapterTraceFiller<F>: Send + Sync {
209 const WIDTH: usize;
210 fn fill_trace_row(&self, mem_helper: &MemoryAuxColsFactory<F>, adapter_row: &mut [F]);
212}
213
214#[derive(Clone, Copy, derive_new::new)]
217pub struct VmAirWrapper<A, C> {
218 pub adapter: A,
219 pub core: C,
220}
221
222impl<F, A, C> BaseAir<F> for VmAirWrapper<A, C>
223where
224 A: BaseAir<F>,
225 C: BaseAir<F>,
226{
227 fn width(&self) -> usize {
228 self.adapter.width() + self.core.width()
229 }
230}
231
232impl<F, A, M> BaseAirWithPublicValues<F> for VmAirWrapper<A, M>
233where
234 A: BaseAir<F>,
235 M: BaseAirWithPublicValues<F>,
236{
237 fn num_public_values(&self) -> usize {
238 self.core.num_public_values()
239 }
240}
241
242impl<F, A, M> PartitionedBaseAir<F> for VmAirWrapper<A, M>
244where
245 A: BaseAir<F>,
246 M: BaseAir<F>,
247{
248}
249
250impl<A, M> ColumnsAir for VmAirWrapper<A, M>
251where
252 A: ColumnsAir,
253 M: ColumnsAir,
254{
255 fn columns(&self) -> Option<Vec<String>> {
256 let adapter_cols = self.adapter.columns()?;
257 let core_cols = self.core.columns()?;
258 Some(adapter_cols.into_iter().chain(core_cols).collect())
259 }
260}
261
262impl<AB, A, M> Air<AB> for VmAirWrapper<A, M>
263where
264 AB: AirBuilder,
265 A: VmAdapterAir<AB>,
266 M: VmCoreAir<AB, A::Interface>,
267{
268 fn eval(&self, builder: &mut AB) {
269 let main = builder.main();
270 let local = main.row_slice(0).expect("window should have two elements");
271 let local: &[AB::Var] = (*local).borrow();
272 let (local_adapter, local_core) = local.split_at(self.adapter.width());
273
274 let ctx = self
275 .core
276 .eval(builder, local_core, self.adapter.get_from_pc(local_adapter));
277 self.adapter.eval(builder, local_adapter, ctx);
278 }
279}
280
281pub struct BasicAdapterInterface<
289 T,
290 PI,
291 const NUM_READS: usize,
292 const NUM_WRITES: usize,
293 const READ_SIZE: usize,
294 const WRITE_SIZE: usize,
295>(PhantomData<T>, PhantomData<PI>);
296
297impl<
298 T,
299 PI,
300 const NUM_READS: usize,
301 const NUM_WRITES: usize,
302 const READ_SIZE: usize,
303 const WRITE_SIZE: usize,
304 > VmAdapterInterface<T>
305 for BasicAdapterInterface<T, PI, NUM_READS, NUM_WRITES, READ_SIZE, WRITE_SIZE>
306{
307 type Reads = [[T; READ_SIZE]; NUM_READS];
308 type Writes = [[T; WRITE_SIZE]; NUM_WRITES];
309 type ProcessedInstruction = PI;
310}
311
312pub struct VecHeapAdapterInterface<
313 T,
314 const NUM_READS: usize,
315 const BLOCKS_PER_READ: usize,
316 const BLOCKS_PER_WRITE: usize,
317 const READ_SIZE: usize,
318 const WRITE_SIZE: usize,
319>(PhantomData<T>);
320
321impl<
322 T,
323 const NUM_READS: usize,
324 const BLOCKS_PER_READ: usize,
325 const BLOCKS_PER_WRITE: usize,
326 const READ_SIZE: usize,
327 const WRITE_SIZE: usize,
328 > VmAdapterInterface<T>
329 for VecHeapAdapterInterface<
330 T,
331 NUM_READS,
332 BLOCKS_PER_READ,
333 BLOCKS_PER_WRITE,
334 READ_SIZE,
335 WRITE_SIZE,
336 >
337{
338 type Reads = [[[T; READ_SIZE]; BLOCKS_PER_READ]; NUM_READS];
339 type Writes = [[T; WRITE_SIZE]; BLOCKS_PER_WRITE];
340 type ProcessedInstruction = MinimalInstruction<T>;
341}
342
343pub struct VecHeapBranchAdapterInterface<
346 T,
347 const NUM_READS: usize,
348 const BLOCKS_PER_READ: usize,
349 const READ_SIZE: usize,
350>(PhantomData<T>);
351
352impl<T, const NUM_READS: usize, const BLOCKS_PER_READ: usize, const READ_SIZE: usize>
353 VmAdapterInterface<T>
354 for VecHeapBranchAdapterInterface<T, NUM_READS, BLOCKS_PER_READ, READ_SIZE>
355{
356 type Reads = [[[T; READ_SIZE]; BLOCKS_PER_READ]; NUM_READS];
357 type Writes = ();
358 type ProcessedInstruction = ImmInstruction<T>;
359}
360
361pub struct FlatInterface<T, PI, const READ_CELLS: usize, const WRITE_CELLS: usize>(
364 PhantomData<T>,
365 PhantomData<PI>,
366);
367
368impl<T, PI, const READ_CELLS: usize, const WRITE_CELLS: usize> VmAdapterInterface<T>
369 for FlatInterface<T, PI, READ_CELLS, WRITE_CELLS>
370{
371 type Reads = [T; READ_CELLS];
372 type Writes = [T; WRITE_CELLS];
373 type ProcessedInstruction = PI;
374}
375
376#[derive(Serialize, Deserialize)]
379pub struct DynAdapterInterface<T>(PhantomData<T>);
380
381impl<T> VmAdapterInterface<T> for DynAdapterInterface<T> {
382 type Reads = DynArray<T>;
384 type Writes = DynArray<T>;
386 type ProcessedInstruction = DynArray<T>;
388}
389
390#[derive(Clone, Debug, Default)]
392pub struct DynArray<T>(pub Vec<T>);
393
394#[repr(C)]
399#[derive(AlignedBorrow, StructReflection)]
400pub struct MinimalInstruction<T> {
401 pub is_valid: T,
402 pub opcode: T,
404}
405
406#[repr(C)]
408#[derive(AlignedBorrow, StructReflection)]
409pub struct ImmInstruction<T> {
410 pub is_valid: T,
411 pub opcode: T,
413 pub immediate: T,
414}
415
416#[repr(C)]
418#[derive(AlignedBorrow, StructReflection)]
419pub struct SignedImmInstruction<T> {
420 pub is_valid: T,
421 pub opcode: T,
423 pub immediate: T,
424 pub imm_sign: T,
426}
427
428mod conversions {
433 use super::*;
434
435 impl<
437 T,
438 const NUM_READS: usize,
439 const BLOCKS_PER_READ: usize,
440 const BLOCKS_PER_WRITE: usize,
441 const READ_SIZE: usize,
442 const WRITE_SIZE: usize,
443 >
444 From<
445 AdapterAirContext<
446 T,
447 VecHeapAdapterInterface<
448 T,
449 NUM_READS,
450 BLOCKS_PER_READ,
451 BLOCKS_PER_WRITE,
452 READ_SIZE,
453 WRITE_SIZE,
454 >,
455 >,
456 > for AdapterAirContext<T, DynAdapterInterface<T>>
457 {
458 fn from(
459 ctx: AdapterAirContext<
460 T,
461 VecHeapAdapterInterface<
462 T,
463 NUM_READS,
464 BLOCKS_PER_READ,
465 BLOCKS_PER_WRITE,
466 READ_SIZE,
467 WRITE_SIZE,
468 >,
469 >,
470 ) -> Self {
471 AdapterAirContext {
472 to_pc: ctx.to_pc,
473 reads: ctx.reads.into(),
474 writes: ctx.writes.into(),
475 instruction: ctx.instruction.into(),
476 }
477 }
478 }
479
480 impl<
482 T,
483 const NUM_READS: usize,
484 const BLOCKS_PER_READ: usize,
485 const BLOCKS_PER_WRITE: usize,
486 const READ_SIZE: usize,
487 const WRITE_SIZE: usize,
488 > From<AdapterAirContext<T, DynAdapterInterface<T>>>
489 for AdapterAirContext<
490 T,
491 VecHeapAdapterInterface<
492 T,
493 NUM_READS,
494 BLOCKS_PER_READ,
495 BLOCKS_PER_WRITE,
496 READ_SIZE,
497 WRITE_SIZE,
498 >,
499 >
500 {
501 fn from(ctx: AdapterAirContext<T, DynAdapterInterface<T>>) -> Self {
502 AdapterAirContext {
503 to_pc: ctx.to_pc,
504 reads: ctx.reads.into(),
505 writes: ctx.writes.into(),
506 instruction: ctx.instruction.into(),
507 }
508 }
509 }
510
511 impl<
513 T,
514 PI: Into<MinimalInstruction<T>>,
515 const BASIC_NUM_READS: usize,
516 const BASIC_NUM_WRITES: usize,
517 const NUM_READS: usize,
518 const BLOCKS_PER_READ: usize,
519 const BLOCKS_PER_WRITE: usize,
520 const READ_SIZE: usize,
521 const WRITE_SIZE: usize,
522 >
523 From<
524 AdapterAirContext<
525 T,
526 BasicAdapterInterface<
527 T,
528 PI,
529 BASIC_NUM_READS,
530 BASIC_NUM_WRITES,
531 READ_SIZE,
532 WRITE_SIZE,
533 >,
534 >,
535 >
536 for AdapterAirContext<
537 T,
538 VecHeapAdapterInterface<
539 T,
540 NUM_READS,
541 BLOCKS_PER_READ,
542 BLOCKS_PER_WRITE,
543 READ_SIZE,
544 WRITE_SIZE,
545 >,
546 >
547 {
548 fn from(
549 ctx: AdapterAirContext<
550 T,
551 BasicAdapterInterface<
552 T,
553 PI,
554 BASIC_NUM_READS,
555 BASIC_NUM_WRITES,
556 READ_SIZE,
557 WRITE_SIZE,
558 >,
559 >,
560 ) -> Self {
561 assert_eq!(BASIC_NUM_READS, NUM_READS * BLOCKS_PER_READ);
562 let mut reads_it = ctx.reads.into_iter();
563 let reads = from_fn(|_| from_fn(|_| reads_it.next().unwrap()));
564 assert_eq!(BASIC_NUM_WRITES, BLOCKS_PER_WRITE);
565 let mut writes_it = ctx.writes.into_iter();
566 let writes = from_fn(|_| writes_it.next().unwrap());
567 AdapterAirContext {
568 to_pc: ctx.to_pc,
569 reads,
570 writes,
571 instruction: ctx.instruction.into(),
572 }
573 }
574 }
575
576 impl<
578 T,
579 PI,
580 const NUM_READS: usize,
581 const NUM_WRITES: usize,
582 const READ_SIZE: usize,
583 const WRITE_SIZE: usize,
584 const READ_CELLS: usize,
585 const WRITE_CELLS: usize,
586 >
587 From<
588 AdapterAirContext<
589 T,
590 BasicAdapterInterface<T, PI, NUM_READS, NUM_WRITES, READ_SIZE, WRITE_SIZE>,
591 >,
592 > for AdapterAirContext<T, FlatInterface<T, PI, READ_CELLS, WRITE_CELLS>>
593 {
594 fn from(
598 ctx: AdapterAirContext<
599 T,
600 BasicAdapterInterface<T, PI, NUM_READS, NUM_WRITES, READ_SIZE, WRITE_SIZE>,
601 >,
602 ) -> AdapterAirContext<T, FlatInterface<T, PI, READ_CELLS, WRITE_CELLS>> {
603 assert_eq!(READ_CELLS, NUM_READS * READ_SIZE);
604 assert_eq!(WRITE_CELLS, NUM_WRITES * WRITE_SIZE);
605 let mut reads_it = ctx.reads.into_iter().flatten();
606 let reads = from_fn(|_| reads_it.next().unwrap());
607 let mut writes_it = ctx.writes.into_iter().flatten();
608 let writes = from_fn(|_| writes_it.next().unwrap());
609 AdapterAirContext {
610 to_pc: ctx.to_pc,
611 reads,
612 writes,
613 instruction: ctx.instruction,
614 }
615 }
616 }
617
618 impl<
620 T,
621 PI,
622 const NUM_READS: usize,
623 const NUM_WRITES: usize,
624 const READ_SIZE: usize,
625 const WRITE_SIZE: usize,
626 const READ_CELLS: usize,
627 const WRITE_CELLS: usize,
628 > From<AdapterAirContext<T, FlatInterface<T, PI, READ_CELLS, WRITE_CELLS>>>
629 for AdapterAirContext<
630 T,
631 BasicAdapterInterface<T, PI, NUM_READS, NUM_WRITES, READ_SIZE, WRITE_SIZE>,
632 >
633 {
634 fn from(
638 AdapterAirContext {
639 to_pc,
640 reads,
641 writes,
642 instruction,
643 }: AdapterAirContext<T, FlatInterface<T, PI, READ_CELLS, WRITE_CELLS>>,
644 ) -> AdapterAirContext<
645 T,
646 BasicAdapterInterface<T, PI, NUM_READS, NUM_WRITES, READ_SIZE, WRITE_SIZE>,
647 > {
648 assert_eq!(READ_CELLS, NUM_READS * READ_SIZE);
649 assert_eq!(WRITE_CELLS, NUM_WRITES * WRITE_SIZE);
650 let mut reads_it = reads.into_iter();
651 let reads: [[T; READ_SIZE]; NUM_READS] =
652 from_fn(|_| from_fn(|_| reads_it.next().unwrap()));
653 let mut writes_it = writes.into_iter();
654 let writes: [[T; WRITE_SIZE]; NUM_WRITES] =
655 from_fn(|_| from_fn(|_| writes_it.next().unwrap()));
656 AdapterAirContext {
657 to_pc,
658 reads,
659 writes,
660 instruction,
661 }
662 }
663 }
664
665 impl<T> From<Vec<T>> for DynArray<T> {
666 fn from(v: Vec<T>) -> Self {
667 Self(v)
668 }
669 }
670
671 impl<T> From<DynArray<T>> for Vec<T> {
672 fn from(v: DynArray<T>) -> Vec<T> {
673 v.0
674 }
675 }
676
677 impl<T, const N: usize, const M: usize> From<[[T; N]; M]> for DynArray<T> {
678 fn from(v: [[T; N]; M]) -> Self {
679 Self(v.into_iter().flatten().collect())
680 }
681 }
682
683 impl<T, const N: usize, const M: usize> From<DynArray<T>> for [[T; N]; M] {
684 fn from(v: DynArray<T>) -> Self {
685 assert_eq!(v.0.len(), N * M, "Incorrect vector length {}", v.0.len());
686 let mut it = v.0.into_iter();
687 from_fn(|_| from_fn(|_| it.next().unwrap()))
688 }
689 }
690
691 impl<T, const N: usize, const M: usize, const R: usize> From<[[[T; N]; M]; R]> for DynArray<T> {
692 fn from(v: [[[T; N]; M]; R]) -> Self {
693 Self(
694 v.into_iter()
695 .flat_map(|x| x.into_iter().flatten())
696 .collect(),
697 )
698 }
699 }
700
701 impl<T, const N: usize, const M: usize, const R: usize> From<DynArray<T>> for [[[T; N]; M]; R] {
702 fn from(v: DynArray<T>) -> Self {
703 assert_eq!(
704 v.0.len(),
705 N * M * R,
706 "Incorrect vector length {}",
707 v.0.len()
708 );
709 let mut it = v.0.into_iter();
710 from_fn(|_| from_fn(|_| from_fn(|_| it.next().unwrap())))
711 }
712 }
713
714 impl<T, const N: usize, const M1: usize, const M2: usize> From<([[T; N]; M1], [[T; N]; M2])>
715 for DynArray<T>
716 {
717 fn from(v: ([[T; N]; M1], [[T; N]; M2])) -> Self {
718 let vec =
719 v.0.into_iter()
720 .flatten()
721 .chain(v.1.into_iter().flatten())
722 .collect();
723 Self(vec)
724 }
725 }
726
727 impl<T, const N: usize, const M1: usize, const M2: usize> From<DynArray<T>>
728 for ([[T; N]; M1], [[T; N]; M2])
729 {
730 fn from(v: DynArray<T>) -> Self {
731 assert_eq!(
732 v.0.len(),
733 N * (M1 + M2),
734 "Incorrect vector length {}",
735 v.0.len()
736 );
737 let mut it = v.0.into_iter();
738 (
739 from_fn(|_| from_fn(|_| it.next().unwrap())),
740 from_fn(|_| from_fn(|_| it.next().unwrap())),
741 )
742 }
743 }
744
745 impl<
747 T,
748 PI: Into<DynArray<T>>,
749 const NUM_READS: usize,
750 const NUM_WRITES: usize,
751 const READ_SIZE: usize,
752 const WRITE_SIZE: usize,
753 >
754 From<
755 AdapterAirContext<
756 T,
757 BasicAdapterInterface<T, PI, NUM_READS, NUM_WRITES, READ_SIZE, WRITE_SIZE>,
758 >,
759 > for AdapterAirContext<T, DynAdapterInterface<T>>
760 {
761 fn from(
762 ctx: AdapterAirContext<
763 T,
764 BasicAdapterInterface<T, PI, NUM_READS, NUM_WRITES, READ_SIZE, WRITE_SIZE>,
765 >,
766 ) -> Self {
767 AdapterAirContext {
768 to_pc: ctx.to_pc,
769 reads: ctx.reads.into(),
770 writes: ctx.writes.into(),
771 instruction: ctx.instruction.into(),
772 }
773 }
774 }
775
776 impl<
778 T,
779 PI,
780 const NUM_READS: usize,
781 const NUM_WRITES: usize,
782 const READ_SIZE: usize,
783 const WRITE_SIZE: usize,
784 > From<AdapterAirContext<T, DynAdapterInterface<T>>>
785 for AdapterAirContext<
786 T,
787 BasicAdapterInterface<T, PI, NUM_READS, NUM_WRITES, READ_SIZE, WRITE_SIZE>,
788 >
789 where
790 PI: From<DynArray<T>>,
791 {
792 fn from(ctx: AdapterAirContext<T, DynAdapterInterface<T>>) -> Self {
793 AdapterAirContext {
794 to_pc: ctx.to_pc,
795 reads: ctx.reads.into(),
796 writes: ctx.writes.into(),
797 instruction: ctx.instruction.into(),
798 }
799 }
800 }
801
802 impl<T: Clone, PI: Into<DynArray<T>>, const READ_CELLS: usize, const WRITE_CELLS: usize>
804 From<AdapterAirContext<T, FlatInterface<T, PI, READ_CELLS, WRITE_CELLS>>>
805 for AdapterAirContext<T, DynAdapterInterface<T>>
806 {
807 fn from(ctx: AdapterAirContext<T, FlatInterface<T, PI, READ_CELLS, WRITE_CELLS>>) -> Self {
808 AdapterAirContext {
809 to_pc: ctx.to_pc,
810 reads: ctx.reads.to_vec().into(),
811 writes: ctx.writes.to_vec().into(),
812 instruction: ctx.instruction.into(),
813 }
814 }
815 }
816
817 impl<T> From<MinimalInstruction<T>> for DynArray<T> {
818 fn from(m: MinimalInstruction<T>) -> Self {
819 Self(vec![m.is_valid, m.opcode])
820 }
821 }
822
823 impl<T> From<DynArray<T>> for MinimalInstruction<T> {
824 fn from(m: DynArray<T>) -> Self {
825 let mut m = m.0.into_iter();
826 MinimalInstruction {
827 is_valid: m.next().unwrap(),
828 opcode: m.next().unwrap(),
829 }
830 }
831 }
832
833 impl<T> From<DynArray<T>> for ImmInstruction<T> {
834 fn from(m: DynArray<T>) -> Self {
835 let mut m = m.0.into_iter();
836 ImmInstruction {
837 is_valid: m.next().unwrap(),
838 opcode: m.next().unwrap(),
839 immediate: m.next().unwrap(),
840 }
841 }
842 }
843
844 impl<T> From<ImmInstruction<T>> for DynArray<T> {
845 fn from(instruction: ImmInstruction<T>) -> Self {
846 DynArray::from(vec![
847 instruction.is_valid,
848 instruction.opcode,
849 instruction.immediate,
850 ])
851 }
852 }
853
854 impl<
856 T,
857 const BASIC_NUM_READS: usize,
858 const NUM_READS: usize,
859 const BLOCKS_PER_READ: usize,
860 const READ_SIZE: usize,
861 >
862 From<
863 AdapterAirContext<
864 T,
865 BasicAdapterInterface<T, ImmInstruction<T>, BASIC_NUM_READS, 0, READ_SIZE, 0>,
866 >,
867 >
868 for AdapterAirContext<
869 T,
870 VecHeapBranchAdapterInterface<T, NUM_READS, BLOCKS_PER_READ, READ_SIZE>,
871 >
872 {
873 fn from(
874 ctx: AdapterAirContext<
875 T,
876 BasicAdapterInterface<T, ImmInstruction<T>, BASIC_NUM_READS, 0, READ_SIZE, 0>,
877 >,
878 ) -> Self {
879 assert_eq!(BASIC_NUM_READS, NUM_READS * BLOCKS_PER_READ);
880 let mut reads_it = ctx.reads.into_iter();
881 let reads = from_fn(|_| from_fn(|_| reads_it.next().unwrap()));
882 AdapterAirContext {
883 to_pc: ctx.to_pc,
884 reads,
885 writes: (),
886 instruction: ctx.instruction,
887 }
888 }
889 }
890}