Skip to main content

rexlang_engine/
runtime_env.rs

1use crate::engine::{
2    CompiledProgram, Engine, RuntimeCapabilities, RuntimeCompatibility, RuntimeLinkContract,
3    RuntimeSnapshot, class_method_capability_matches_requirement,
4    native_capability_matches_requirement,
5};
6use crate::{EngineError, EvalError};
7
8#[derive(Clone)]
9pub struct RuntimeEnv<State = ()>
10where
11    State: Clone + Send + Sync + 'static,
12{
13    pub(crate) loader: Engine<State>,
14    pub(crate) runtime: RuntimeSnapshot<State>,
15    capabilities: RuntimeCapabilities,
16}
17
18fn runtime_compatibility(
19    contract: &RuntimeLinkContract,
20    capabilities: &RuntimeCapabilities,
21) -> RuntimeCompatibility {
22    let mut missing_natives = Vec::new();
23    let mut incompatible_natives = Vec::new();
24    for requirement in &contract.natives {
25        match capabilities.native_impls.get(&requirement.name) {
26            None => missing_natives.push(requirement.name.clone()),
27            Some(impls) => {
28                if !impls.iter().any(|capability| {
29                    native_capability_matches_requirement(capability, requirement)
30                }) {
31                    incompatible_natives.push(requirement.name.clone());
32                }
33            }
34        }
35    }
36
37    let mut missing_class_methods = Vec::new();
38    let mut incompatible_class_methods = Vec::new();
39    for requirement in &contract.class_methods {
40        match capabilities.class_method_impls.get(&requirement.name) {
41            None => missing_class_methods.push(requirement.name.clone()),
42            Some(capability) => {
43                if !class_method_capability_matches_requirement(capability, requirement) {
44                    incompatible_class_methods.push(requirement.name.clone());
45                }
46            }
47        }
48    }
49
50    RuntimeCompatibility {
51        expected_abi_version: contract.abi_version,
52        actual_abi_version: capabilities.abi_version,
53        missing_natives,
54        incompatible_natives,
55        missing_class_methods,
56        incompatible_class_methods,
57    }
58}
59
60impl<State> RuntimeEnv<State>
61where
62    State: Clone + Send + Sync + 'static,
63{
64    pub fn new(engine: Engine<State>) -> Self {
65        let capabilities = engine.runtime_capabilities_snapshot();
66        let runtime = engine.runtime_snapshot();
67        Self {
68            loader: engine,
69            runtime,
70            capabilities,
71        }
72    }
73
74    pub fn capabilities(&self) -> &RuntimeCapabilities {
75        &self.capabilities
76    }
77
78    pub fn fingerprint(&self) -> u64 {
79        self.capabilities.fingerprint()
80    }
81
82    pub fn compatibility_with(&self, program: &CompiledProgram) -> RuntimeCompatibility {
83        runtime_compatibility(program.link_contract(), &self.capabilities)
84    }
85
86    pub fn validate(&self, program: &CompiledProgram) -> Result<(), EvalError> {
87        self.validate_internal(program).map_err(EvalError::from)
88    }
89
90    pub(crate) fn validate_internal(&self, program: &CompiledProgram) -> Result<(), EngineError> {
91        let compatibility = self.compatibility_with(program);
92        if compatibility.is_compatible() {
93            Ok(())
94        } else {
95            Err(EngineError::Link {
96                expected_abi_version: compatibility.expected_abi_version,
97                actual_abi_version: compatibility.actual_abi_version,
98                missing_natives: compatibility.missing_natives,
99                incompatible_natives: compatibility.incompatible_natives,
100                missing_class_methods: compatibility.missing_class_methods,
101                incompatible_class_methods: compatibility.incompatible_class_methods,
102            })
103        }
104    }
105
106    pub(crate) fn sync_from_engine(&mut self, engine: &Engine<State>) {
107        self.loader = engine.clone();
108        self.runtime = engine.runtime_snapshot();
109        self.capabilities = engine.runtime_capabilities_snapshot();
110    }
111
112    pub fn storage_boundary(&self) -> RuntimeEnvBoundary {
113        RuntimeEnvBoundary {
114            contains_runtime_snapshot: true,
115            contains_loader_state: true,
116            serializable: false,
117        }
118    }
119}
120
121#[derive(Clone, Copy, Debug, PartialEq, Eq)]
122pub struct RuntimeEnvBoundary {
123    pub contains_runtime_snapshot: bool,
124    pub contains_loader_state: bool,
125    pub serializable: bool,
126}