use crate::{gas, visitors};
use super::{BranchTargetKind, Frame};
pub trait Config<'b> {
    type GasVisitor<'s>: visitors::VisitOperatorWithOffset<'b, Output = Result<(), gas::Error>>
    where
        Self: 's;
    fn make_visitor<'s>(&'s mut self, state: &'s mut gas::FunctionState) -> Self::GasVisitor<'s>;
    fn save_outcomes(
        &self,
        state: &mut gas::FunctionState,
        destination: &mut crate::AnalysisOutcome,
    );
}
impl<'b> Config<'b> for crate::NoConfig {
    type GasVisitor<'s> = visitors::NoOpVisitor<Result<(), gas::Error>>;
    fn make_visitor<'s>(&'s mut self, _: &'s mut gas::FunctionState) -> Self::GasVisitor<'s> {
        visitors::NoOpVisitor(Ok(()))
    }
    fn save_outcomes(&self, _: &mut gas::FunctionState, _: &mut crate::AnalysisOutcome) {}
}
impl<'b, V: wasmparser::VisitOperator<'b, Output = u64>> Config<'b> for V {
    type GasVisitor<'s> = gas::Visitor<'s, V> where Self: 's;
    fn make_visitor<'s>(&'s mut self, state: &'s mut gas::FunctionState) -> Self::GasVisitor<'s> {
        gas::Visitor {
            offset: 0,
            model: self,
            state,
        }
    }
    fn save_outcomes(&self, state: &mut gas::FunctionState, out: &mut crate::AnalysisOutcome) {
        state.optimize();
        out.gas_offsets.push(state.offsets.drain(..).collect());
        out.gas_kinds.push(state.kinds.drain(..).collect());
        out.gas_costs.push(state.costs.drain(..).collect());
        state.frame_stack.clear();
        state.current_frame = Frame {
            stack_polymorphic: false,
            kind: BranchTargetKind::UntakenForward,
        };
        state.scheduled_instrumentation = None;
    }
}