#![doc = essential_asm_gen::gen_ops_docs_table!()]
#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(unsafe_code)]
#![warn(missing_docs)]
#[doc(inline)]
pub use essential_constraint_asm::{FromBytesError, Word};
#[doc(inline)]
pub use op::{StateRead as Op, *};
#[doc(inline)]
pub use opcode::{InvalidOpcodeError, NotEnoughBytesError, StateRead as Opcode};
mod op {
pub use essential_constraint_asm::{
Access, Alu, Constraint, Crypto, Pred, Stack, Temporary, ToBytes, ToOpcode,
TotalControlFlow, TryFromBytes,
};
essential_asm_gen::gen_state_read_op_decls!();
essential_asm_gen::gen_state_read_op_impls!();
pub mod bytes_iter {
pub use essential_constraint_asm::bytes_iter::*;
essential_asm_gen::gen_state_read_op_bytes_iter!();
}
}
pub mod opcode {
pub use essential_constraint_asm::opcode::*;
essential_asm_gen::gen_state_read_opcode_decls!();
essential_asm_gen::gen_state_read_opcode_impls!();
}
pub fn from_bytes(
bytes: impl IntoIterator<Item = u8>,
) -> impl Iterator<Item = Result<Op, FromBytesError>> {
let mut iter = bytes.into_iter();
core::iter::from_fn(move || Op::try_from_bytes(&mut iter))
}
pub fn to_bytes(ops: impl IntoIterator<Item = Op>) -> impl Iterator<Item = u8> {
ops.into_iter().flat_map(|op| op.to_bytes())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn opcode_roundtrip_u8() {
for byte in 0..=u8::MAX {
if let Ok(opcode) = Opcode::try_from(byte) {
println!("{byte:02X}: {opcode:?}");
assert_eq!(u8::from(opcode), byte);
}
}
}
fn roundtrip(ops: Vec<Op>) {
assert!(!ops.is_empty());
let bytes: Vec<_> = to_bytes(ops.iter().cloned()).collect();
assert_eq!(
ops,
from_bytes(bytes).collect::<Result<Vec<_>, _>>().unwrap()
);
}
#[test]
fn roundtrip_args_start() {
let ops: Vec<Op> = vec![
Stack::Push(0x1234567812345678).into(),
Stack::Push(0x0F0F0F0F0F0F0F0F).into(),
StateSlots::AllocSlots.into(),
StateSlots::Length.into(),
];
roundtrip(ops);
}
#[test]
#[allow(clippy::useless_conversion)]
fn roundtrip_args_end() {
let ops: Vec<Op> = vec![
StateRead::KeyRange.into(),
StateRead::KeyRangeExtern.into(),
Stack::Push(0x0F0F0F0F0F0F0F0F).into(),
];
roundtrip(ops);
}
#[test]
fn roundtrip_no_args() {
let ops: Vec<Op> = vec![
StateSlots::Store.into(),
Access::ThisAddress.into(),
StateSlots::Load.into(),
Access::ThisContractAddress.into(),
StateSlots::Length.into(),
];
roundtrip(ops);
}
fn expect_invalid_opcode(opcode_byte: u8) {
let bytes = vec![opcode_byte];
let err = from_bytes(bytes)
.collect::<Result<Vec<_>, _>>()
.unwrap_err();
match err {
FromBytesError::InvalidOpcode(InvalidOpcodeError(byte)) => {
assert_eq!(byte, opcode_byte)
}
_ => panic!("unexpected error variant"),
}
}
#[test]
fn invalid_opcode_0x00() {
let opcode_byte = 0x00;
expect_invalid_opcode(opcode_byte);
}
#[test]
fn invalid_opcode_0xff() {
let opcode_byte = 0xFF;
expect_invalid_opcode(opcode_byte);
}
}