Coverage Report

Created: 2026-02-20 14:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/build/source/src/execution/resumable.rs
Line
Count
Source
1
use core::num::NonZeroU64;
2
3
use alloc::vec::Vec;
4
5
use crate::{
6
    addrs::FuncAddr,
7
    core::slotmap::{SlotMap, SlotMapKey},
8
    value_stack::Stack,
9
    Value,
10
};
11
12
#[derive(Debug)]
13
pub(crate) struct Resumable {
14
    pub(crate) stack: Stack,
15
    pub(crate) pc: usize,
16
    pub(crate) stp: usize,
17
    pub(crate) current_func_addr: FuncAddr,
18
    pub(crate) maybe_fuel: Option<u64>,
19
}
20
21
#[derive(Default)]
22
pub(crate) struct Dormitory(SlotMap<Resumable>);
23
24
impl Dormitory {
25
50
    pub(crate) fn insert(&mut self, resumable: Resumable) -> InvokedResumableRef {
26
50
        let key = self.0.insert(resumable);
27
50
        InvokedResumableRef { key }
28
50
    }
29
30
43
    pub(crate) fn get_mut(
31
43
        &mut self,
32
43
        resumable_ref: &InvokedResumableRef,
33
43
    ) -> Option<&mut Resumable> {
34
43
        self.0.get_mut(&resumable_ref.key)
35
43
    }
36
37
44
    pub(crate) fn remove(&mut self, resumable_ref: InvokedResumableRef) -> Option<Resumable> {
38
44
        self.0.remove(&resumable_ref.key)
39
44
    }
40
}
41
42
/// # Note
43
///
44
/// Dropping a resumable ref does not deallocate the resumable anymore. It is up
45
/// to the user to implement such garbage collection algorithms by using
46
/// [`Store::drop_resumable`](crate::Store::drop_resumable) to prevent unnecessary memory usage.
47
pub struct InvokedResumableRef {
48
    pub(crate) key: SlotMapKey<Resumable>,
49
}
50
51
pub struct FreshResumableRef {
52
    pub(crate) func_addr: FuncAddr,
53
    pub(crate) params: Vec<Value>,
54
    pub(crate) maybe_fuel: Option<u64>,
55
}
56
57
/// An object associated to a resumable that is held internally.
58
pub enum ResumableRef {
59
    /// indicates this resumable has never been invoked/resumed to.
60
    Fresh(FreshResumableRef),
61
    /// indicates this resumable has been invoked/resumed to at least once.
62
    Invoked(InvokedResumableRef),
63
}
64
65
/// Represents the state of a possibly interrupted resumable.
66
pub enum RunState {
67
    /// represents a resumable that has executed completely with return values `values` and possibly remaining fuel
68
    /// `maybe_remaining_fuel` (has `Some(remaining_fuel)` for fuel-metered operations and `None` otherwise)
69
    Finished {
70
        values: Vec<Value>,
71
        maybe_remaining_fuel: Option<u64>,
72
    },
73
    /// represents a resumable that has ran out of fuel during execution, missing at least `required_fuel` units of fuel
74
    /// to continue further execution.
75
    Resumable {
76
        resumable_ref: ResumableRef,
77
        required_fuel: NonZeroU64,
78
    },
79
}
80
81
#[cfg(test)]
82
mod test {
83
    use alloc::vec::Vec;
84
85
    use crate::{
86
        addrs::{Addr, FuncAddr},
87
        core::reader::types::{FuncType, ResultType},
88
        value_stack::Stack,
89
    };
90
91
    use super::{Dormitory, Resumable};
92
93
    /// Test that a dormitory can be constructed and that a resumable can be inserted
94
    #[test]
95
1
    fn dormitory_constructor() {
96
1
        let mut dorm = Dormitory::default();
97
98
1
        let empty_stack = Stack::new::<()>(
99
1
            Vec::new(),
100
1
            &FuncType {
101
1
                params: ResultType {
102
1
                    valtypes: Vec::new(),
103
1
                },
104
1
                returns: ResultType {
105
1
                    valtypes: Vec::new(),
106
1
                },
107
1
            },
108
1
            &[],
109
        )
110
1
        .unwrap();
111
112
1
        let resumable = Resumable {
113
1
            stack: empty_stack,
114
1
            pc: 11,
115
1
            stp: 13,
116
1
            current_func_addr: FuncAddr::new_unchecked(0),
117
1
            maybe_fuel: None,
118
1
        };
119
120
1
        dorm.insert(resumable);
121
1
    }
122
}