use fuel_tx::Receipt;
use fuel_types::{Bytes32, Word};
#[cfg(feature = "debug")]
mod debug;
#[cfg(feature = "debug")]
mod debugger;
#[cfg(feature = "debug")]
pub use debug::{Breakpoint, DebugEval};
#[cfg(feature = "debug")]
pub use debugger::Debugger;
#[cfg(not(feature = "debug"))]
pub type Debugger = ();
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ExecuteState {
Proceed,
Return(Word),
ReturnData(Bytes32),
Revert(Word),
#[cfg(feature = "debug")]
DebugEvent(DebugEval),
}
impl ExecuteState {
pub const fn should_continue(&self) -> bool {
#[cfg(not(feature = "debug"))]
{
matches!(self, Self::Proceed)
}
#[cfg(feature = "debug")]
{
matches!(self, Self::Proceed | Self::DebugEvent(DebugEval::Continue))
}
}
}
impl Default for ExecuteState {
fn default() -> Self {
Self::Proceed
}
}
#[cfg(feature = "debug")]
impl From<DebugEval> for ExecuteState {
fn from(d: DebugEval) -> Self {
Self::DebugEvent(d)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ProgramState {
Return(Word),
ReturnData(Bytes32),
Revert(Word),
#[cfg(feature = "debug")]
RunProgram(DebugEval),
#[cfg(feature = "debug")]
VerifyPredicate(DebugEval),
}
#[cfg(feature = "debug")]
impl PartialEq<Breakpoint> for ProgramState {
fn eq(&self, other: &Breakpoint) -> bool {
match self.debug_ref() {
Some(&DebugEval::Breakpoint(b)) => &b == other,
_ => false,
}
}
}
#[cfg(feature = "debug")]
impl ProgramState {
pub const fn debug_ref(&self) -> Option<&DebugEval> {
match self {
Self::RunProgram(d) | Self::VerifyPredicate(d) => Some(d),
_ => None,
}
}
pub const fn is_debug(&self) -> bool {
self.debug_ref().is_some()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StateTransition<Tx> {
state: ProgramState,
tx: Tx,
receipts: Vec<Receipt>,
}
impl<Tx> StateTransition<Tx> {
pub const fn new(state: ProgramState, tx: Tx, receipts: Vec<Receipt>) -> Self {
Self { state, tx, receipts }
}
pub const fn state(&self) -> &ProgramState {
&self.state
}
pub const fn tx(&self) -> &Tx {
&self.tx
}
pub fn should_revert(&self) -> bool {
self.receipts
.iter()
.any(|r| matches!(r, Receipt::Revert { .. } | Receipt::Panic { .. }))
}
pub fn receipts(&self) -> &[Receipt] {
self.receipts.as_slice()
}
pub fn into_inner(self) -> (ProgramState, Tx, Vec<Receipt>) {
(self.state, self.tx, self.receipts)
}
}
impl<Tx> From<StateTransition<Tx>> for ProgramState {
fn from(t: StateTransition<Tx>) -> ProgramState {
t.state
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct StateTransitionRef<'a, Tx> {
state: ProgramState,
tx: &'a Tx,
receipts: &'a [Receipt],
}
impl<'a, Tx> StateTransitionRef<'a, Tx> {
pub const fn new(state: ProgramState, tx: &'a Tx, receipts: &'a [Receipt]) -> Self {
Self { state, tx, receipts }
}
pub const fn state(&self) -> &ProgramState {
&self.state
}
pub const fn tx(&self) -> &Tx {
self.tx
}
pub const fn receipts(&self) -> &[Receipt] {
self.receipts
}
pub fn should_revert(&self) -> bool {
self.receipts
.iter()
.any(|r| matches!(r, Receipt::Revert { .. } | Receipt::Panic { .. }))
}
}
impl<'a, Tx> From<&'a StateTransition<Tx>> for StateTransitionRef<'a, Tx> {
fn from(t: &'a StateTransition<Tx>) -> StateTransitionRef<'a, Tx> {
Self {
state: *t.state(),
tx: t.tx(),
receipts: t.receipts(),
}
}
}
impl<'a, Tx: Clone> From<StateTransitionRef<'a, Tx>> for StateTransition<Tx> {
fn from(t: StateTransitionRef<Tx>) -> StateTransition<Tx> {
StateTransition {
state: *t.state(),
tx: t.tx().clone(),
receipts: t.receipts().to_vec(),
}
}
}
impl<'a, Tx: Clone> From<StateTransitionRef<'a, Tx>> for ProgramState {
fn from(t: StateTransitionRef<'a, Tx>) -> ProgramState {
t.state
}
}