rexlang_engine/
runtime_env.rs1use 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}