essential_state_asm/
lib.rs1#![doc = essential_asm_gen::gen_ops_docs_table!()]
5#![cfg_attr(not(feature = "std"), no_std)]
6#![forbid(unsafe_code)]
7#![warn(missing_docs)]
8
9#[doc(inline)]
10pub use essential_constraint_asm::{FromBytesError, Word};
11#[doc(inline)]
12pub use op::{StateRead as Op, *};
13#[doc(inline)]
14pub use opcode::{InvalidOpcodeError, NotEnoughBytesError, StateRead as Opcode};
15
16mod op {
18 pub use essential_constraint_asm::{
19 Access, Alu, Constraint, Crypto, Pred, Stack, Temporary, ToBytes, ToOpcode,
20 TotalControlFlow, TryFromBytes,
21 };
22 essential_asm_gen::gen_state_read_op_decls!();
23 essential_asm_gen::gen_state_read_op_impls!();
24 pub mod bytes_iter {
26 pub use essential_constraint_asm::bytes_iter::*;
27 essential_asm_gen::gen_state_read_op_bytes_iter!();
28 }
29
30 pub mod short {
32 use super::{StateRead as Op, *};
33 essential_asm_gen::gen_state_op_consts!();
34 }
35}
36
37pub mod opcode {
39 pub use essential_constraint_asm::opcode::*;
40 essential_asm_gen::gen_state_read_opcode_decls!();
41 essential_asm_gen::gen_state_read_opcode_impls!();
42}
43
44pub fn from_bytes(
50 bytes: impl IntoIterator<Item = u8>,
51) -> impl Iterator<Item = Result<Op, FromBytesError>> {
52 let mut iter = bytes.into_iter();
53 core::iter::from_fn(move || Op::try_from_bytes(&mut iter))
54}
55
56pub fn to_bytes(ops: impl IntoIterator<Item = Op>) -> impl Iterator<Item = u8> {
59 ops.into_iter().flat_map(|op| op.to_bytes())
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn opcode_roundtrip_u8() {
68 for byte in 0..=u8::MAX {
69 if let Ok(opcode) = Opcode::try_from(byte) {
70 println!("{byte:02X}: {opcode:?}");
71 assert_eq!(u8::from(opcode), byte);
72 }
73 }
74 }
75
76 fn roundtrip(ops: Vec<Op>) {
77 assert!(!ops.is_empty());
78 let bytes: Vec<_> = to_bytes(ops.iter().cloned()).collect();
79 assert_eq!(
80 ops,
81 from_bytes(bytes).collect::<Result<Vec<_>, _>>().unwrap()
82 );
83 }
84
85 #[test]
86 fn roundtrip_args_start() {
87 let ops: Vec<Op> = vec![
88 Stack::Push(0x1234567812345678).into(),
89 Stack::Push(0x0F0F0F0F0F0F0F0F).into(),
90 StateMemory::AllocSlots.into(),
91 StateMemory::Length.into(),
92 ];
93 roundtrip(ops);
94 }
95
96 #[test]
97 #[allow(clippy::useless_conversion)]
98 fn roundtrip_args_end() {
99 let ops: Vec<Op> = vec![
100 StateRead::KeyRange.into(),
101 StateRead::KeyRangeExtern.into(),
102 Stack::Push(0x0F0F0F0F0F0F0F0F).into(),
103 ];
104 roundtrip(ops);
105 }
106
107 #[test]
108 fn roundtrip_no_args() {
109 let ops: Vec<Op> = vec![
110 StateMemory::Store.into(),
111 Access::ThisAddress.into(),
112 StateMemory::Load.into(),
113 Access::ThisContractAddress.into(),
114 StateMemory::Length.into(),
115 ];
116 roundtrip(ops);
117 }
118
119 fn expect_invalid_opcode(opcode_byte: u8) {
120 let bytes = vec![opcode_byte];
121 let err = from_bytes(bytes)
122 .collect::<Result<Vec<_>, _>>()
123 .unwrap_err();
124 match err {
125 FromBytesError::InvalidOpcode(InvalidOpcodeError(byte)) => {
126 assert_eq!(byte, opcode_byte)
127 }
128 _ => panic!("unexpected error variant"),
129 }
130 }
131
132 #[test]
133 fn invalid_opcode_0x00() {
134 let opcode_byte = 0x00;
135 expect_invalid_opcode(opcode_byte);
136 }
137
138 #[test]
139 fn invalid_opcode_0xff() {
140 let opcode_byte = 0xFF;
141 expect_invalid_opcode(opcode_byte);
142 }
143}