telltale_machine/engine/runtime_state/
program_store.rs1fn default_instruction_cost() -> usize {
3 1
4}
5
6fn default_initial_cost_budget() -> usize {
7 usize::MAX
8}
9
10fn default_config_schema_version() -> u32 {
11 1
12}
13
14fn default_max_payload_bytes() -> usize {
15 64 * 1024
16}
17
18pub(crate) type ScopeId = usize;
20
21pub type Program = Box<[Instr]>;
23
24#[derive(Debug, Clone, Default, Serialize, Deserialize)]
26pub struct ProgramStore {
27 programs: Vec<Program>,
28 #[serde(default)]
29 cache: BTreeMap<Vec<u8>, usize>,
30}
31
32impl ProgramStore {
33 #[must_use]
35 pub fn new() -> Self {
36 Self::default()
37 }
38
39 fn ensure_cache_initialized(&mut self) {
40 if self.cache.len() == self.programs.len() {
41 return;
42 }
43 self.cache.clear();
44 for (idx, program) in self.programs.iter().enumerate() {
45 self.cache.insert(Self::cache_key(program), idx);
46 }
47 }
48
49 fn cache_key(program: &[Instr]) -> Vec<u8> {
50 crate::serialization::binary_encode(program)
51 .expect("program serialization for cache key should succeed")
52 }
53
54 pub fn reserve(&mut self, additional: usize) {
56 self.programs.reserve(additional);
57 }
58
59 pub fn intern(&mut self, program: Vec<Instr>) -> usize {
61 self.ensure_cache_initialized();
62 let key = Self::cache_key(&program);
63 if let Some(existing) = self.cache.get(&key) {
64 return *existing;
65 }
66 let program_id = self.programs.len();
67 self.programs.push(program.into_boxed_slice());
68 self.cache.insert(key, program_id);
69 program_id
70 }
71
72 #[must_use]
74 pub fn get(&self, program_id: usize) -> Option<&Program> {
75 self.programs.get(program_id)
76 }
77
78 #[must_use]
80 pub fn len(&self) -> usize {
81 self.programs.len()
82 }
83
84 #[must_use]
86 pub fn is_empty(&self) -> bool {
87 self.programs.is_empty()
88 }
89
90 #[must_use]
92 pub fn instruction_count(&self) -> usize {
93 self.programs.iter().map(|program| program.len()).sum()
94 }
95
96 #[cfg(test)]
97 fn replace_for_test(&mut self, program_id: usize, program: Vec<Instr>) {
98 self.ensure_cache_initialized();
99 if let Some(existing) = self.programs.get(program_id) {
100 let key = Self::cache_key(existing);
101 self.cache.remove(&key);
102 }
103 self.programs[program_id] = program.into_boxed_slice();
104 let new_key = Self::cache_key(&self.programs[program_id]);
105 self.cache.insert(new_key, program_id);
106 }
107}
108
109type BranchList = Vec<(
111 telltale_types::Label,
112 Option<telltale_types::ValType>,
113 LocalTypeR,
114)>;
115
116pub(crate) fn runtime_value_val_type(value: &Value) -> ValType {
118 match value {
119 Value::Unit => ValType::Unit,
120 Value::Nat(_) => ValType::Nat,
121 Value::Bool(_) => ValType::Bool,
122 Value::Str(_) => ValType::String,
123 Value::Prod(left, right) => ValType::Prod(
124 Box::new(runtime_value_val_type(left)),
125 Box::new(runtime_value_val_type(right)),
126 ),
127 Value::Endpoint(endpoint) => ValType::Chan {
128 sid: endpoint.sid,
129 role: endpoint.role.clone(),
130 },
131 }
132}
133
134pub(crate) fn runtime_value_wire_size_bytes(value: &Value) -> usize {
136 match value {
137 Value::Unit => 1,
138 Value::Nat(_) => 8,
139 Value::Bool(_) => 1,
140 Value::Str(text) => 8_usize.saturating_add(text.len()),
141 Value::Prod(left, right) => 1_usize
142 .saturating_add(runtime_value_wire_size_bytes(left))
143 .saturating_add(runtime_value_wire_size_bytes(right)),
144 Value::Endpoint(endpoint) => 8_usize
145 .saturating_add(8_usize)
146 .saturating_add(endpoint.role.len()),
147 }
148}
149
150pub(crate) fn runtime_value_matches_val_type(value: &Value, expected: &ValType) -> bool {
152 match (value, expected) {
153 (Value::Unit, ValType::Unit) => true,
154 (Value::Nat(_), ValType::Nat) => true,
155 (Value::Bool(_), ValType::Bool) => true,
156 (Value::Str(_), ValType::String) => true,
157 (Value::Prod(left, right), ValType::Prod(expected_left, expected_right)) => {
158 runtime_value_matches_val_type(left, expected_left)
159 && runtime_value_matches_val_type(right, expected_right)
160 }
161 (Value::Endpoint(endpoint), ValType::Chan { sid, role }) => {
162 endpoint.sid == *sid && endpoint.role == *role
163 }
164 _ => false,
165 }
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize, Default)]
170pub struct ResourceState {
171 commitments: BTreeSet<crate::verification::Commitment>,
172 nullifiers: BTreeSet<crate::verification::Nullifier>,
173}
174
175impl ResourceState {
176 #[must_use]
178 pub fn commit(&mut self, value: &Value) -> crate::verification::Commitment {
179 let commitment = crate::verification::DefaultVerificationModel::commitment(value);
180 self.commitments.insert(commitment);
181 commitment
182 }
183
184 pub fn consume(&mut self, value: &Value) -> Result<crate::verification::Nullifier, String> {
190 let nullifier = crate::verification::DefaultVerificationModel::nullifier(value);
191 if self.nullifiers.contains(&nullifier) {
192 return Err("resource already consumed".to_string());
193 }
194 self.nullifiers.insert(nullifier);
195 Ok(nullifier)
196 }
197
198 #[must_use]
200 pub fn verify_uncommitted(&self, value: &Value) -> bool {
201 let nullifier = crate::verification::DefaultVerificationModel::nullifier(value);
202 !self.nullifiers.contains(&nullifier)
203 }
204}