/build/source/src/execution/resumable.rs
Line | Count | Source |
1 | | use core::num::NonZeroU32; |
2 | | |
3 | | use alloc::{ |
4 | | sync::{Arc, Weak}, |
5 | | vec::Vec, |
6 | | }; |
7 | | |
8 | | use crate::{ |
9 | | addrs::FuncAddr, |
10 | | core::slotmap::{SlotMap, SlotMapKey}, |
11 | | rw_spinlock::RwSpinLock, |
12 | | value_stack::Stack, |
13 | | Value, |
14 | | }; |
15 | | |
16 | | #[derive(Debug)] |
17 | | pub(crate) struct Resumable { |
18 | | pub(crate) stack: Stack, |
19 | | pub(crate) pc: usize, |
20 | | pub(crate) stp: usize, |
21 | | pub(crate) current_func_addr: FuncAddr, |
22 | | pub(crate) maybe_fuel: Option<u32>, |
23 | | } |
24 | | |
25 | | #[derive(Default)] |
26 | | pub(crate) struct Dormitory(pub(crate) Arc<RwSpinLock<SlotMap<Resumable>>>); |
27 | | |
28 | | impl Dormitory { |
29 | | #[allow(unused)] |
30 | 1 | pub(crate) fn new() -> Self { |
31 | 1 | Self::default() |
32 | 1 | } |
33 | | |
34 | 8 | pub(crate) fn insert(&self, resumable: Resumable) -> InvokedResumableRef { |
35 | 8 | let key = self.0.write().insert(resumable); |
36 | 8 | |
37 | 8 | InvokedResumableRef { |
38 | 8 | dormitory: Arc::downgrade(&self.0), |
39 | 8 | key, |
40 | 8 | } |
41 | 8 | } |
42 | | } |
43 | | |
44 | | pub struct InvokedResumableRef { |
45 | | pub(crate) dormitory: Weak<RwSpinLock<SlotMap<Resumable>>>, |
46 | | pub(crate) key: SlotMapKey<Resumable>, |
47 | | } |
48 | | |
49 | | pub struct FreshResumableRef { |
50 | | pub(crate) func_addr: FuncAddr, |
51 | | pub(crate) params: Vec<Value>, |
52 | | pub(crate) maybe_fuel: Option<u32>, |
53 | | } |
54 | | |
55 | | /// An object associated to a resumable that is held internally. |
56 | | pub enum ResumableRef { |
57 | | /// indicates this resumable has never been invoked/resumed to. |
58 | | Fresh(FreshResumableRef), |
59 | | /// indicates this resumable has been invoked/resumed to at least once. |
60 | | Invoked(InvokedResumableRef), |
61 | | } |
62 | | |
63 | | impl Drop for InvokedResumableRef { |
64 | 8 | fn drop(&mut self) { |
65 | 8 | let Some(dormitory7 ) = self.dormitory.upgrade() else { |
66 | | // Either the dormitory was already dropped or `self` was used to finish execution. |
67 | 1 | return; |
68 | | }; |
69 | | |
70 | 7 | dormitory.write().remove(&self.key) |
71 | 7 | .expect("that the resumable could not have been removed already, because then this self could not exist or the dormitory weak pointer would have been None"); |
72 | 8 | } |
73 | | } |
74 | | |
75 | | /// Represents the state of a possibly interrupted resumable. |
76 | | pub enum RunState { |
77 | | /// represents a resumable that has executed completely with return values `values` and possibly remaining fuel |
78 | | /// `maybe_remaining_fuel` (has `Some(remaining_fuel)` for fuel-metered operations and `None` otherwise) |
79 | | Finished { |
80 | | values: Vec<Value>, |
81 | | maybe_remaining_fuel: Option<u32>, |
82 | | }, |
83 | | /// represents a resumable that has ran out of fuel during execution, missing at least `required_fuel` units of fuel |
84 | | /// to continue further execution. |
85 | | Resumable { |
86 | | resumable_ref: ResumableRef, |
87 | | required_fuel: NonZeroU32, |
88 | | }, |
89 | | } |
90 | | |
91 | | #[cfg(test)] |
92 | | mod test { |
93 | | use crate::{addrs::FuncAddr, value_stack::Stack}; |
94 | | |
95 | | use super::{Dormitory, Resumable}; |
96 | | |
97 | | /// Test that a dormitory can be constructed and that a resumable can be inserted |
98 | | #[test] |
99 | 1 | fn dormitory_constructor() { |
100 | 1 | let dorm = Dormitory::new(); |
101 | 1 | |
102 | 1 | let resumable = Resumable { |
103 | 1 | stack: Stack::new(), |
104 | 1 | pc: 11, |
105 | 1 | stp: 13, |
106 | 1 | current_func_addr: FuncAddr::INVALID, |
107 | 1 | maybe_fuel: None, |
108 | 1 | }; |
109 | 1 | |
110 | 1 | dorm.insert(resumable); |
111 | 1 | } |
112 | | } |