Skip to main content

datex_core/runtime/execution/
execution_input.rs

1use crate::runtime::{
2    RuntimeInternal,
3    execution::{
4        ExecutionError,
5        execution_loop::{
6            interrupts::{ExternalExecutionInterrupt, InterruptProvider},
7            state::{ExecutionLoopState, RuntimeExecutionSlots},
8        },
9    },
10};
11
12use crate::prelude::*;
13#[derive(Debug, Clone, Default)]
14pub struct ExecutionOptions {
15    pub verbose: bool,
16}
17
18/// Input required to execute a DXB program.
19#[derive(Debug)]
20pub struct ExecutionInput<'a> {
21    /// Options for execution.
22    pub options: ExecutionOptions,
23    /// The DXB program body containing raw bytecode.
24    pub dxb_body: &'a [u8],
25    /// For persisting execution state across multiple executions (e.g., for REPL scenarios).
26    pub loop_state: Option<ExecutionLoopState>,
27    pub runtime: Rc<RuntimeInternal>,
28}
29
30impl<'a> ExecutionInput<'a> {
31    pub fn new(
32        dxb_body: &'a [u8],
33        options: ExecutionOptions,
34        runtime: Rc<RuntimeInternal>,
35    ) -> Self {
36        Self {
37            options,
38            dxb_body,
39            loop_state: None,
40            runtime,
41        }
42    }
43    pub fn new_with_slots(
44        dxb_body: &'a [u8],
45        options: ExecutionOptions,
46        runtime: Rc<RuntimeInternal>,
47        slots: RuntimeExecutionSlots,
48    ) -> Self {
49        let state =
50            ExecutionLoopState::new(dxb_body.to_vec(), runtime.clone(), slots);
51        Self {
52            options,
53            dxb_body,
54            loop_state: Some(state),
55            runtime,
56        }
57    }
58
59    pub fn execution_loop(
60        mut self,
61    ) -> (
62        InterruptProvider,
63        impl Iterator<Item = Result<ExternalExecutionInterrupt, ExecutionError>>,
64    ) {
65        // use execution iterator if one already exists from previous execution
66        let mut loop_state = if let Some(existing_loop_state) =
67            self.loop_state.take()
68        {
69            // update dxb so that instruction iterator can continue with next instructions
70            *existing_loop_state.dxb_body.borrow_mut() = self.dxb_body.to_vec();
71            existing_loop_state
72        }
73        // otherwise start a new execution loop
74        else {
75            ExecutionLoopState::new(
76                self.dxb_body.to_vec(),
77                self.runtime.clone(),
78                Default::default(),
79            )
80        };
81        let interrupt_provider = loop_state.interrupt_provider.clone();
82
83        // proxy the iterator, storing it back into state if interrupted to await more instructions
84        let iterator = gen move {
85            loop {
86                let item = loop_state.iterator.next();
87                if item.is_none() {
88                    break;
89                }
90                let item = item.unwrap();
91
92                match item {
93                    Err(ExecutionError::IntermediateResultWithState(
94                        intermediate_result,
95                        _,
96                    )) => {
97                        yield Err(ExecutionError::IntermediateResultWithState(
98                            intermediate_result,
99                            Some(loop_state),
100                        ));
101                        break;
102                    }
103                    _ => yield item,
104                }
105            }
106        };
107
108        (interrupt_provider, iterator)
109    }
110}