essential_state_asm/
lib.rs#![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 short {
        use super::{StateRead as Op, *};
        essential_asm_gen::gen_state_op_consts!();
    }
}
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(),
            StateMemory::AllocSlots.into(),
            StateMemory::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![
            StateMemory::Store.into(),
            Access::ThisAddress.into(),
            StateMemory::Load.into(),
            Access::ThisContractAddress.into(),
            StateMemory::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);
    }
}