1fn default_instruction_cost() -> usize {
2 1
3}
4
5fn default_initial_cost_budget() -> usize {
6 usize::MAX
7}
8
9fn default_config_schema_version() -> u32 {
10 1
11}
12
13fn default_max_payload_bytes() -> usize {
14 64 * 1024
15}
16
17pub type ScopeId = usize;
19
20pub type Program = Vec<Instr>;
22
23type BranchList = Vec<(
25 telltale_types::Label,
26 Option<telltale_types::ValType>,
27 LocalTypeR,
28)>;
29
30pub(crate) fn runtime_value_val_type(value: &Value) -> ValType {
32 match value {
33 Value::Unit => ValType::Unit,
34 Value::Nat(_) => ValType::Nat,
35 Value::Bool(_) => ValType::Bool,
36 Value::Str(_) => ValType::String,
37 Value::Prod(left, right) => ValType::Prod(
38 Box::new(runtime_value_val_type(left)),
39 Box::new(runtime_value_val_type(right)),
40 ),
41 Value::Endpoint(endpoint) => ValType::Chan {
42 sid: endpoint.sid,
43 role: endpoint.role.clone(),
44 },
45 }
46}
47
48pub(crate) fn runtime_value_wire_size_bytes(value: &Value) -> usize {
50 match value {
51 Value::Unit => 1,
52 Value::Nat(_) => 8,
53 Value::Bool(_) => 1,
54 Value::Str(text) => 8_usize.saturating_add(text.len()),
55 Value::Prod(left, right) => 1_usize
56 .saturating_add(runtime_value_wire_size_bytes(left))
57 .saturating_add(runtime_value_wire_size_bytes(right)),
58 Value::Endpoint(endpoint) => 8_usize
59 .saturating_add(8_usize)
60 .saturating_add(endpoint.role.len()),
61 }
62}
63
64pub(crate) fn runtime_value_matches_val_type(value: &Value, expected: &ValType) -> bool {
66 match (value, expected) {
67 (Value::Unit, ValType::Unit) => true,
68 (Value::Nat(_), ValType::Nat) => true,
69 (Value::Bool(_), ValType::Bool) => true,
70 (Value::Str(_), ValType::String) => true,
71 (Value::Prod(left, right), ValType::Prod(expected_left, expected_right)) => {
72 runtime_value_matches_val_type(left, expected_left)
73 && runtime_value_matches_val_type(right, expected_right)
74 }
75 (Value::Endpoint(endpoint), ValType::Chan { sid, role }) => {
76 endpoint.sid == *sid && endpoint.role == *role
77 }
78 _ => false,
79 }
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize, Default)]
84pub struct ResourceState {
85 commitments: BTreeSet<crate::verification::Commitment>,
86 nullifiers: BTreeSet<crate::verification::Nullifier>,
87}
88
89impl ResourceState {
90 #[must_use]
92 pub fn commit(&mut self, value: &Value) -> crate::verification::Commitment {
93 let commitment = crate::verification::DefaultVerificationModel::commitment(value);
94 self.commitments.insert(commitment);
95 commitment
96 }
97
98 pub fn consume(&mut self, value: &Value) -> Result<crate::verification::Nullifier, String> {
104 let nullifier = crate::verification::DefaultVerificationModel::nullifier(value);
105 if self.nullifiers.contains(&nullifier) {
106 return Err("resource already consumed".to_string());
107 }
108 self.nullifiers.insert(nullifier);
109 Ok(nullifier)
110 }
111
112 #[must_use]
114 pub fn verify_uncommitted(&self, value: &Value) -> bool {
115 let nullifier = crate::verification::DefaultVerificationModel::nullifier(value);
116 !self.nullifiers.contains(&nullifier)
117 }
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct Arena {
123 slots: Vec<Option<Value>>,
124 next_free: usize,
125 capacity: usize,
126}
127
128impl Default for Arena {
129 fn default() -> Self {
130 Self::new(128)
131 }
132}
133
134impl Arena {
135 #[must_use]
137 pub fn new(capacity: usize) -> Self {
138 let cap = capacity.max(1);
139 Self {
140 slots: vec![None; cap],
141 next_free: 0,
142 capacity: cap,
143 }
144 }
145
146 pub fn alloc(&mut self, value: Value) -> Result<usize, String> {
152 for offset in 0..self.capacity {
153 let idx = (self.next_free + offset) % self.capacity;
154 if self.slots[idx].is_none() {
155 self.slots[idx] = Some(value);
156 self.next_free = (idx + 1) % self.capacity;
157 debug_assert!(self.check_invariants());
158 return Ok(idx);
159 }
160 }
161 Err("arena full".to_string())
162 }
163
164 pub fn free(&mut self, idx: usize) -> Result<Value, String> {
170 if idx >= self.capacity {
171 return Err("arena index out of bounds".to_string());
172 }
173 let value = self.slots[idx]
174 .take()
175 .ok_or_else(|| "arena slot already free".to_string())?;
176 if idx < self.next_free {
177 self.next_free = idx;
178 }
179 debug_assert!(self.check_invariants());
180 Ok(value)
181 }
182
183 #[must_use]
185 pub fn get(&self, idx: usize) -> Option<&Value> {
186 self.slots.get(idx).and_then(Option::as_ref)
187 }
188
189 pub fn get_mut(&mut self, idx: usize) -> Option<&mut Value> {
191 self.slots.get_mut(idx).and_then(Option::as_mut)
192 }
193
194 #[must_use]
196 pub fn check_invariants(&self) -> bool {
197 self.slots.len() == self.capacity && self.next_free < self.capacity
198 }
199}
200
201#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
203pub enum SessionKind {
204 Client,
206 Server,
208 Peer,
210}
211
212#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
214pub struct WellTypedInstr {
215 pub endpoint: Endpoint,
217 pub instr_tag: String,
219 pub tick: u64,
221}
222
223#[derive(Debug, Clone, Serialize, Deserialize, Default)]
225pub struct SessionMonitor {
226 session_kinds: BTreeMap<SessionId, SessionKind>,
227 last_judgment: Option<WellTypedInstr>,
228}
229
230impl SessionMonitor {
231 pub fn set_kind(&mut self, sid: SessionId, kind: SessionKind) {
233 self.session_kinds.insert(sid, kind);
234 }
235
236 pub fn remove_kind(&mut self, sid: SessionId) {
238 self.session_kinds.remove(&sid);
239 }
240
241 pub fn record(&mut self, endpoint: &Endpoint, instr_tag: &str, tick: u64) {
243 self.last_judgment = Some(WellTypedInstr {
244 endpoint: endpoint.clone(),
245 instr_tag: instr_tag.to_string(),
246 tick,
247 });
248 }
249}
250
251pub type SiteId = String;
253
254#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
256pub struct CorruptedEdge {
257 edge: Edge,
258 corruption: CorruptionType,
259}
260
261#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
263pub struct SiteTimeout {
264 site: SiteId,
265 until_tick: u64,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct GuardLayerConfig {
271 pub id: String,
273 pub active: bool,
275}
276
277#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
279pub enum MonitorMode {
280 Off,
282 #[default]
284 SessionTypePrecheck,
285}
286
287pub enum FlowPolicy {
289 AllowAll,
291 DenyAll,
293 AllowRoles(BTreeSet<String>),
295 DenyRoles(BTreeSet<String>),
297 Predicate(Box<dyn FlowPolicyFn>),
300 PredicateExpr(FlowPredicate),
302}
303
304pub trait FlowPolicyFn: Send + Sync {
306 fn eval(&self, knowledge: &KnowledgeFact, target_role: &str) -> bool;
308 fn clone_box(&self) -> Box<dyn FlowPolicyFn>;
310}
311
312impl<F> FlowPolicyFn for F
313where
314 F: Fn(&KnowledgeFact, &str) -> bool + Clone + Send + Sync + 'static,
315{
316 fn eval(&self, knowledge: &KnowledgeFact, target_role: &str) -> bool {
317 self(knowledge, target_role)
318 }
319
320 fn clone_box(&self) -> Box<dyn FlowPolicyFn> {
321 Box::new(self.clone())
322 }
323}
324
325impl Clone for Box<dyn FlowPolicyFn> {
326 fn clone(&self) -> Self {
327 self.clone_box()
328 }
329}
330
331#[allow(clippy::derivable_impls)]
332impl Default for FlowPolicy {
333 fn default() -> Self {
334 Self::AllowAll
335 }
336}
337
338impl Clone for FlowPolicy {
339 fn clone(&self) -> Self {
340 match self {
341 Self::AllowAll => Self::AllowAll,
342 Self::DenyAll => Self::DenyAll,
343 Self::AllowRoles(roles) => Self::AllowRoles(roles.clone()),
344 Self::DenyRoles(roles) => Self::DenyRoles(roles.clone()),
345 Self::Predicate(predicate) => Self::Predicate(predicate.clone()),
346 Self::PredicateExpr(predicate) => Self::PredicateExpr(predicate.clone()),
347 }
348 }
349}
350
351impl fmt::Debug for FlowPolicy {
352 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353 match self {
354 Self::AllowAll => f.write_str("AllowAll"),
355 Self::DenyAll => f.write_str("DenyAll"),
356 Self::AllowRoles(roles) => f.debug_tuple("AllowRoles").field(roles).finish(),
357 Self::DenyRoles(roles) => f.debug_tuple("DenyRoles").field(roles).finish(),
358 Self::Predicate(_) => f.write_str("Predicate(<dynamic>)"),
359 Self::PredicateExpr(predicate) => {
360 f.debug_tuple("PredicateExpr").field(predicate).finish()
361 }
362 }
363 }
364}
365
366impl PartialEq for FlowPolicy {
367 fn eq(&self, other: &Self) -> bool {
368 match (self, other) {
369 (Self::AllowAll, Self::AllowAll) => true,
370 (Self::DenyAll, Self::DenyAll) => true,
371 (Self::AllowRoles(lhs), Self::AllowRoles(rhs)) => lhs == rhs,
372 (Self::DenyRoles(lhs), Self::DenyRoles(rhs)) => lhs == rhs,
373 (Self::Predicate(lhs), Self::Predicate(rhs)) => {
374 std::ptr::eq::<dyn FlowPolicyFn>(&**lhs, &**rhs)
378 }
379 (Self::PredicateExpr(lhs), Self::PredicateExpr(rhs)) => lhs == rhs,
380 _ => false,
381 }
382 }
383}
384
385impl Eq for FlowPolicy {}
386
387#[derive(Serialize, Deserialize)]
388enum FlowPolicyRepr {
389 AllowAll,
390 DenyAll,
391 AllowRoles(BTreeSet<String>),
392 DenyRoles(BTreeSet<String>),
393 PredicateExpr(FlowPredicate),
394}
395
396impl Serialize for FlowPolicy {
397 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
398 where
399 S: Serializer,
400 {
401 let repr = match self {
402 Self::AllowAll => FlowPolicyRepr::AllowAll,
403 Self::DenyAll => FlowPolicyRepr::DenyAll,
404 Self::AllowRoles(roles) => FlowPolicyRepr::AllowRoles(roles.clone()),
405 Self::DenyRoles(roles) => FlowPolicyRepr::DenyRoles(roles.clone()),
406 Self::PredicateExpr(predicate) => FlowPolicyRepr::PredicateExpr(predicate.clone()),
407 Self::Predicate(_) => {
408 return Err(serde::ser::Error::custom(
409 "runtime closure predicate is not serializable",
410 ))
411 }
412 };
413 repr.serialize(serializer)
414 }
415}
416
417impl<'de> Deserialize<'de> for FlowPolicy {
418 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
419 where
420 D: Deserializer<'de>,
421 {
422 let repr = FlowPolicyRepr::deserialize(deserializer)?;
423 let policy = match repr {
424 FlowPolicyRepr::AllowAll => Self::AllowAll,
425 FlowPolicyRepr::DenyAll => Self::DenyAll,
426 FlowPolicyRepr::AllowRoles(roles) => Self::AllowRoles(roles),
427 FlowPolicyRepr::DenyRoles(roles) => Self::DenyRoles(roles),
428 FlowPolicyRepr::PredicateExpr(predicate) => Self::PredicateExpr(predicate),
429 };
430 Ok(policy)
431 }
432}
433
434impl FlowPolicy {
435 #[must_use]
437 pub fn predicate<F>(predicate: F) -> Self
438 where
439 F: Fn(&KnowledgeFact, &str) -> bool + Clone + Send + Sync + 'static,
440 {
441 Self::Predicate(Box::new(predicate))
442 }
443}
444
445#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
447pub enum FlowPredicate {
448 TargetRolePrefix(String),
450 FactContains(String),
452 EndpointRoleMatchesTarget,
454 All(Vec<FlowPredicate>),
456 Any(Vec<FlowPredicate>),
458}
459
460impl FlowPolicy {
461 #[must_use]
463 pub fn allows(&self, target_role: &str) -> bool {
464 match self {
465 Self::AllowAll => true,
466 Self::DenyAll => false,
467 Self::AllowRoles(roles) => roles.contains(target_role),
468 Self::DenyRoles(roles) => !roles.contains(target_role),
469 Self::Predicate(_) | Self::PredicateExpr(_) => true,
470 }
471 }
472
473 #[must_use]
475 pub fn allows_knowledge(&self, knowledge: &KnowledgeFact, target_role: &str) -> bool {
476 match self {
477 Self::Predicate(predicate) => predicate.eval(knowledge, target_role),
478 Self::PredicateExpr(predicate) => predicate.eval(knowledge, target_role),
479 other => other.allows(target_role),
480 }
481 }
482}
483
484impl FlowPredicate {
485 #[must_use]
487 pub fn eval(&self, knowledge: &KnowledgeFact, target_role: &str) -> bool {
488 match self {
489 Self::TargetRolePrefix(prefix) => target_role.starts_with(prefix),
490 Self::FactContains(fragment) => knowledge.fact.contains(fragment),
491 Self::EndpointRoleMatchesTarget => knowledge.endpoint.role == target_role,
492 Self::All(predicates) => predicates
493 .iter()
494 .all(|predicate| predicate.eval(knowledge, target_role)),
495 Self::Any(predicates) => predicates
496 .iter()
497 .any(|predicate| predicate.eval(knowledge, target_role)),
498 }
499 }
500}
501
502#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
504#[serde(rename_all = "snake_case")]
505pub enum RuntimeTuningProfile {
506 #[default]
508 Standard,
509 M1StressReference,
511}
512
513#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
515#[serde(rename_all = "snake_case")]
516pub enum ThreadedRoundSemantics {
517 #[default]
519 CanonicalOneStep,
520 WaveParallelExtension,
522}
523
524#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
526#[serde(rename_all = "snake_case")]
527pub enum EffectTraceCaptureMode {
528 #[default]
530 Full,
531 TopologyOnly,
533 Disabled,
535}
536
537#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
539#[serde(rename_all = "snake_case")]
540pub enum PayloadValidationMode {
541 Off,
543 #[default]
545 Structural,
546 StrictSchema,
548}
549