fn default_instruction_cost() -> usize {
1
}
fn default_initial_cost_budget() -> usize {
usize::MAX
}
fn default_config_schema_version() -> u32 {
1
}
fn default_max_payload_bytes() -> usize {
64 * 1024
}
pub type ScopeId = usize;
pub type Program = Vec<Instr>;
type BranchList = Vec<(
telltale_types::Label,
Option<telltale_types::ValType>,
LocalTypeR,
)>;
pub(crate) fn runtime_value_val_type(value: &Value) -> ValType {
match value {
Value::Unit => ValType::Unit,
Value::Nat(_) => ValType::Nat,
Value::Bool(_) => ValType::Bool,
Value::Str(_) => ValType::String,
Value::Prod(left, right) => ValType::Prod(
Box::new(runtime_value_val_type(left)),
Box::new(runtime_value_val_type(right)),
),
Value::Endpoint(endpoint) => ValType::Chan {
sid: endpoint.sid,
role: endpoint.role.clone(),
},
}
}
pub(crate) fn runtime_value_wire_size_bytes(value: &Value) -> usize {
match value {
Value::Unit => 1,
Value::Nat(_) => 8,
Value::Bool(_) => 1,
Value::Str(text) => 8_usize.saturating_add(text.len()),
Value::Prod(left, right) => 1_usize
.saturating_add(runtime_value_wire_size_bytes(left))
.saturating_add(runtime_value_wire_size_bytes(right)),
Value::Endpoint(endpoint) => 8_usize
.saturating_add(8_usize)
.saturating_add(endpoint.role.len()),
}
}
pub(crate) fn runtime_value_matches_val_type(value: &Value, expected: &ValType) -> bool {
match (value, expected) {
(Value::Unit, ValType::Unit) => true,
(Value::Nat(_), ValType::Nat) => true,
(Value::Bool(_), ValType::Bool) => true,
(Value::Str(_), ValType::String) => true,
(Value::Prod(left, right), ValType::Prod(expected_left, expected_right)) => {
runtime_value_matches_val_type(left, expected_left)
&& runtime_value_matches_val_type(right, expected_right)
}
(Value::Endpoint(endpoint), ValType::Chan { sid, role }) => {
endpoint.sid == *sid && endpoint.role == *role
}
_ => false,
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ResourceState {
commitments: BTreeSet<crate::verification::Commitment>,
nullifiers: BTreeSet<crate::verification::Nullifier>,
}
impl ResourceState {
#[must_use]
pub fn commit(&mut self, value: &Value) -> crate::verification::Commitment {
let commitment = crate::verification::DefaultVerificationModel::commitment(value);
self.commitments.insert(commitment);
commitment
}
pub fn consume(&mut self, value: &Value) -> Result<crate::verification::Nullifier, String> {
let nullifier = crate::verification::DefaultVerificationModel::nullifier(value);
if self.nullifiers.contains(&nullifier) {
return Err("resource already consumed".to_string());
}
self.nullifiers.insert(nullifier);
Ok(nullifier)
}
#[must_use]
pub fn verify_uncommitted(&self, value: &Value) -> bool {
let nullifier = crate::verification::DefaultVerificationModel::nullifier(value);
!self.nullifiers.contains(&nullifier)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Arena {
slots: Vec<Option<Value>>,
next_free: usize,
capacity: usize,
}
impl Default for Arena {
fn default() -> Self {
Self::new(128)
}
}
impl Arena {
#[must_use]
pub fn new(capacity: usize) -> Self {
let cap = capacity.max(1);
Self {
slots: vec![None; cap],
next_free: 0,
capacity: cap,
}
}
pub fn alloc(&mut self, value: Value) -> Result<usize, String> {
for offset in 0..self.capacity {
let idx = (self.next_free + offset) % self.capacity;
if self.slots[idx].is_none() {
self.slots[idx] = Some(value);
self.next_free = (idx + 1) % self.capacity;
debug_assert!(self.check_invariants());
return Ok(idx);
}
}
Err("arena full".to_string())
}
pub fn free(&mut self, idx: usize) -> Result<Value, String> {
if idx >= self.capacity {
return Err("arena index out of bounds".to_string());
}
let value = self.slots[idx]
.take()
.ok_or_else(|| "arena slot already free".to_string())?;
if idx < self.next_free {
self.next_free = idx;
}
debug_assert!(self.check_invariants());
Ok(value)
}
#[must_use]
pub fn get(&self, idx: usize) -> Option<&Value> {
self.slots.get(idx).and_then(Option::as_ref)
}
pub fn get_mut(&mut self, idx: usize) -> Option<&mut Value> {
self.slots.get_mut(idx).and_then(Option::as_mut)
}
#[must_use]
pub fn check_invariants(&self) -> bool {
self.slots.len() == self.capacity && self.next_free < self.capacity
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SessionKind {
Client,
Server,
Peer,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct WellTypedInstr {
pub endpoint: Endpoint,
pub instr_tag: String,
pub tick: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SessionMonitor {
session_kinds: BTreeMap<SessionId, SessionKind>,
last_judgment: Option<WellTypedInstr>,
}
impl SessionMonitor {
pub fn set_kind(&mut self, sid: SessionId, kind: SessionKind) {
self.session_kinds.insert(sid, kind);
}
pub fn remove_kind(&mut self, sid: SessionId) {
self.session_kinds.remove(&sid);
}
pub fn record(&mut self, endpoint: &Endpoint, instr_tag: &str, tick: u64) {
self.last_judgment = Some(WellTypedInstr {
endpoint: endpoint.clone(),
instr_tag: instr_tag.to_string(),
tick,
});
}
}
pub type SiteId = String;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct CorruptedEdge {
edge: Edge,
corruption: CorruptionType,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct SiteTimeout {
site: SiteId,
until_tick: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GuardLayerConfig {
pub id: String,
pub active: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum MonitorMode {
Off,
#[default]
SessionTypePrecheck,
}
pub enum FlowPolicy {
AllowAll,
DenyAll,
AllowRoles(BTreeSet<String>),
DenyRoles(BTreeSet<String>),
Predicate(Box<dyn FlowPolicyFn>),
PredicateExpr(FlowPredicate),
}
pub trait FlowPolicyFn: Send + Sync {
fn eval(&self, knowledge: &KnowledgeFact, target_role: &str) -> bool;
fn clone_box(&self) -> Box<dyn FlowPolicyFn>;
}
impl<F> FlowPolicyFn for F
where
F: Fn(&KnowledgeFact, &str) -> bool + Clone + Send + Sync + 'static,
{
fn eval(&self, knowledge: &KnowledgeFact, target_role: &str) -> bool {
self(knowledge, target_role)
}
fn clone_box(&self) -> Box<dyn FlowPolicyFn> {
Box::new(self.clone())
}
}
impl Clone for Box<dyn FlowPolicyFn> {
fn clone(&self) -> Self {
self.clone_box()
}
}
#[allow(clippy::derivable_impls)]
impl Default for FlowPolicy {
fn default() -> Self {
Self::AllowAll
}
}
impl Clone for FlowPolicy {
fn clone(&self) -> Self {
match self {
Self::AllowAll => Self::AllowAll,
Self::DenyAll => Self::DenyAll,
Self::AllowRoles(roles) => Self::AllowRoles(roles.clone()),
Self::DenyRoles(roles) => Self::DenyRoles(roles.clone()),
Self::Predicate(predicate) => Self::Predicate(predicate.clone()),
Self::PredicateExpr(predicate) => Self::PredicateExpr(predicate.clone()),
}
}
}
impl fmt::Debug for FlowPolicy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::AllowAll => f.write_str("AllowAll"),
Self::DenyAll => f.write_str("DenyAll"),
Self::AllowRoles(roles) => f.debug_tuple("AllowRoles").field(roles).finish(),
Self::DenyRoles(roles) => f.debug_tuple("DenyRoles").field(roles).finish(),
Self::Predicate(_) => f.write_str("Predicate(<dynamic>)"),
Self::PredicateExpr(predicate) => {
f.debug_tuple("PredicateExpr").field(predicate).finish()
}
}
}
}
impl PartialEq for FlowPolicy {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::AllowAll, Self::AllowAll) => true,
(Self::DenyAll, Self::DenyAll) => true,
(Self::AllowRoles(lhs), Self::AllowRoles(rhs)) => lhs == rhs,
(Self::DenyRoles(lhs), Self::DenyRoles(rhs)) => lhs == rhs,
(Self::Predicate(lhs), Self::Predicate(rhs)) => {
std::ptr::eq::<dyn FlowPolicyFn>(&**lhs, &**rhs)
}
(Self::PredicateExpr(lhs), Self::PredicateExpr(rhs)) => lhs == rhs,
_ => false,
}
}
}
impl Eq for FlowPolicy {}
#[derive(Serialize, Deserialize)]
enum FlowPolicyRepr {
AllowAll,
DenyAll,
AllowRoles(BTreeSet<String>),
DenyRoles(BTreeSet<String>),
PredicateExpr(FlowPredicate),
}
impl Serialize for FlowPolicy {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let repr = match self {
Self::AllowAll => FlowPolicyRepr::AllowAll,
Self::DenyAll => FlowPolicyRepr::DenyAll,
Self::AllowRoles(roles) => FlowPolicyRepr::AllowRoles(roles.clone()),
Self::DenyRoles(roles) => FlowPolicyRepr::DenyRoles(roles.clone()),
Self::PredicateExpr(predicate) => FlowPolicyRepr::PredicateExpr(predicate.clone()),
Self::Predicate(_) => {
return Err(serde::ser::Error::custom(
"runtime closure predicate is not serializable",
))
}
};
repr.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for FlowPolicy {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let repr = FlowPolicyRepr::deserialize(deserializer)?;
let policy = match repr {
FlowPolicyRepr::AllowAll => Self::AllowAll,
FlowPolicyRepr::DenyAll => Self::DenyAll,
FlowPolicyRepr::AllowRoles(roles) => Self::AllowRoles(roles),
FlowPolicyRepr::DenyRoles(roles) => Self::DenyRoles(roles),
FlowPolicyRepr::PredicateExpr(predicate) => Self::PredicateExpr(predicate),
};
Ok(policy)
}
}
impl FlowPolicy {
#[must_use]
pub fn predicate<F>(predicate: F) -> Self
where
F: Fn(&KnowledgeFact, &str) -> bool + Clone + Send + Sync + 'static,
{
Self::Predicate(Box::new(predicate))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum FlowPredicate {
TargetRolePrefix(String),
FactContains(String),
EndpointRoleMatchesTarget,
All(Vec<FlowPredicate>),
Any(Vec<FlowPredicate>),
}
impl FlowPolicy {
#[must_use]
pub fn allows(&self, target_role: &str) -> bool {
match self {
Self::AllowAll => true,
Self::DenyAll => false,
Self::AllowRoles(roles) => roles.contains(target_role),
Self::DenyRoles(roles) => !roles.contains(target_role),
Self::Predicate(_) | Self::PredicateExpr(_) => true,
}
}
#[must_use]
pub fn allows_knowledge(&self, knowledge: &KnowledgeFact, target_role: &str) -> bool {
match self {
Self::Predicate(predicate) => predicate.eval(knowledge, target_role),
Self::PredicateExpr(predicate) => predicate.eval(knowledge, target_role),
other => other.allows(target_role),
}
}
}
impl FlowPredicate {
#[must_use]
pub fn eval(&self, knowledge: &KnowledgeFact, target_role: &str) -> bool {
match self {
Self::TargetRolePrefix(prefix) => target_role.starts_with(prefix),
Self::FactContains(fragment) => knowledge.fact.contains(fragment),
Self::EndpointRoleMatchesTarget => knowledge.endpoint.role == target_role,
Self::All(predicates) => predicates
.iter()
.all(|predicate| predicate.eval(knowledge, target_role)),
Self::Any(predicates) => predicates
.iter()
.any(|predicate| predicate.eval(knowledge, target_role)),
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeTuningProfile {
#[default]
Standard,
M1StressReference,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum ThreadedRoundSemantics {
#[default]
CanonicalOneStep,
WaveParallelExtension,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum EffectTraceCaptureMode {
#[default]
Full,
TopologyOnly,
Disabled,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum PayloadValidationMode {
Off,
#[default]
Structural,
StrictSchema,
}