use alloc::sync::Arc;
use core::ops::ControlFlow;
use crate::{
BreakReason, Host,
continuation_stack::ContinuationStack,
execution::InternalBreakReason,
mast::{MastForest, MastNodeExt, MastNodeId},
operation::OperationError,
processor::Processor,
tracer::Tracer,
};
#[inline(always)]
pub(super) fn execute_external_node(
processor: &mut impl Processor,
external_node_id: MastNodeId,
current_forest: &mut Arc<MastForest>,
host: &mut impl Host,
) -> ControlFlow<InternalBreakReason> {
processor
.execute_before_enter_decorators(external_node_id, current_forest, host)
.map_break(InternalBreakReason::from)?;
let external_node = current_forest[external_node_id].unwrap_external();
ControlFlow::Break(InternalBreakReason::LoadMastForestFromExternal {
external_node_id,
procedure_hash: external_node.digest(),
})
}
pub fn finish_load_mast_forest_from_external(
resolved_node_id: MastNodeId,
new_mast_forest: Arc<MastForest>,
external_node_id: MastNodeId,
current_forest: &mut Arc<MastForest>,
continuation_stack: &mut ContinuationStack,
host: &mut impl Host,
tracer: &mut impl Tracer,
) -> ControlFlow<BreakReason> {
let external_node = current_forest[external_node_id].unwrap_external();
if new_mast_forest[resolved_node_id].is_external() {
return ControlFlow::Break(BreakReason::Err(
OperationError::CircularExternalNode(external_node.digest()).with_context(
current_forest,
external_node_id,
host,
),
));
}
tracer.record_mast_forest_resolution(resolved_node_id, &new_mast_forest);
continuation_stack.push_finish_external(external_node_id);
continuation_stack.push_enter_forest(current_forest.clone());
continuation_stack.push_start_node(resolved_node_id);
*current_forest = new_mast_forest;
ControlFlow::Continue(())
}