Skip to main content

datex_core/runtime/execution/execution_loop/
state.rs

1use crate::{
2    collections::HashMap,
3    runtime::{
4        RuntimeInternal,
5        execution::{
6            ExecutionError,
7            execution_loop::{
8                ExternalExecutionInterrupt, execution_loop,
9                interrupts::InterruptProvider,
10            },
11        },
12    },
13    shared_values::observers::TransceiverId,
14    values::value_container::ValueContainer,
15};
16use core::{cell::RefCell, fmt::Debug};
17
18use crate::prelude::*;
19pub struct ExecutionLoopState {
20    pub iterator: Box<
21        dyn Iterator<Item = Result<ExternalExecutionInterrupt, ExecutionError>>,
22    >,
23    pub dxb_body: Rc<RefCell<Vec<u8>>>,
24    pub(crate) interrupt_provider: InterruptProvider,
25}
26impl ExecutionLoopState {
27    pub fn new(
28        dxb_body: Vec<u8>,
29        runtime: Rc<RuntimeInternal>,
30        slots: RuntimeExecutionSlots,
31    ) -> Self {
32        let state = RuntimeExecutionState {
33            runtime_internal: runtime.clone(),
34            source_id: 0, // TODO #640: set proper source ID
35            slots,
36        };
37        // TODO #641: optimize, don't clone the whole DXB body every time here
38        let dxb_rc = Rc::new(RefCell::new(dxb_body.to_vec()));
39        let interrupt_provider = InterruptProvider::new();
40        ExecutionLoopState {
41            dxb_body: dxb_rc.clone(),
42            iterator: Box::new(execution_loop(
43                state,
44                dxb_rc,
45                interrupt_provider.clone(),
46            )),
47            interrupt_provider,
48        }
49    }
50}
51
52impl Debug for ExecutionLoopState {
53    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54        f.debug_struct("ExecutionIterator")
55            .field("dxb_body_length", &self.dxb_body.borrow().len())
56            .finish()
57    }
58}
59
60#[derive(Debug)]
61pub struct RuntimeExecutionState {
62    /// Local memory slots for current execution context.
63    /// TODO #643: replace this with a local stack and deprecate local slots?
64    pub slots: RuntimeExecutionSlots,
65    pub runtime_internal: Rc<RuntimeInternal>,
66    pub source_id: TransceiverId,
67}
68
69#[derive(Debug, Default)]
70pub struct RuntimeExecutionSlots {
71    pub slots: HashMap<u32, Option<ValueContainer>>,
72}
73
74impl RuntimeExecutionSlots {
75    /// Allocates a new slot with the given slot address.
76    pub(crate) fn allocate_slot(
77        &mut self,
78        address: u32,
79        value: Option<ValueContainer>,
80    ) {
81        self.slots.insert(address, value);
82    }
83
84    /// Drops a slot by its address, returning the value if it existed.
85    /// If the slot is not allocated, it returns an error.
86    pub(crate) fn drop_slot(
87        &mut self,
88        address: u32,
89    ) -> Result<Option<ValueContainer>, ExecutionError> {
90        self.slots
91            .remove(&address)
92            .ok_or(())
93            .map_err(|_| ExecutionError::SlotNotAllocated(address))
94    }
95
96    /// Sets the value of a slot, returning the previous value if it existed.
97    /// If the slot is not allocated, it returns an error.
98    pub(crate) fn set_slot_value(
99        &mut self,
100        address: u32,
101        value: ValueContainer,
102    ) -> Result<Option<ValueContainer>, ExecutionError> {
103        self.slots
104            .insert(address, Some(value))
105            .ok_or(())
106            .map_err(|_| ExecutionError::SlotNotAllocated(address))
107    }
108
109    /// Retrieves a reference to the value of a slot by its address.
110    /// If the slot is not allocated, it returns an error.
111    pub(crate) fn get_slot_value(
112        &self,
113        address: u32,
114    ) -> Result<&ValueContainer, ExecutionError> {
115        self.slots
116            .get(&address)
117            .and_then(|inner| inner.as_ref())
118            .ok_or_else(|| ExecutionError::SlotNotAllocated(address))
119    }
120
121    /// Retrieves a mutable reference to the value of a slot by its address.
122    /// If the slot is not allocated, it returns an error.
123    pub(crate) fn get_slot_value_mut(
124        &mut self,
125        address: u32,
126    ) -> Result<&mut ValueContainer, ExecutionError> {
127        self.slots
128            .get_mut(&address)
129            .and_then(|inner| inner.as_mut())
130            .ok_or_else(|| ExecutionError::SlotNotAllocated(address))
131    }
132}