1use serde::{Deserialize, Serialize};
7use telltale_types::ValType;
8
9use crate::instr::{Endpoint, PC};
10use crate::session::{Edge, HandlerId, SessionId};
11
12fn default_cost_budget() -> usize {
13 usize::MAX
14}
15
16pub type RegFile = Vec<Value>;
18
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21pub struct ProgressToken {
22 pub sid: SessionId,
24 pub endpoint: Endpoint,
26}
27
28impl ProgressToken {
29 #[must_use]
31 pub fn for_endpoint(endpoint: Endpoint) -> Self {
32 Self {
33 sid: endpoint.sid,
34 endpoint,
35 }
36 }
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
41pub struct EffectCtx<E = ()> {
42 pub last_effect: Option<E>,
44}
45
46impl<E> Default for EffectCtx<E> {
47 fn default() -> Self {
48 Self { last_effect: None }
49 }
50}
51
52#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
54pub enum Value {
55 Unit,
57 Nat(u64),
59 Bool(bool),
61 Str(String),
63 Prod(Box<Value>, Box<Value>),
65 Endpoint(Endpoint),
67}
68
69#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
71pub enum CoroStatus {
72 Ready,
74 Blocked(BlockReason),
76 Done,
78 Faulted(Fault),
80 Speculating,
82}
83
84#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
86pub enum BlockReason {
87 Recv {
89 edge: Edge,
91 token: ProgressToken,
93 },
94 Send {
96 edge: Edge,
98 },
99 Invoke {
101 handler: HandlerId,
103 },
104 AcquireDenied {
106 layer: String,
108 },
109 Consensus {
111 tag: usize,
113 },
114 Spawn,
116 Close {
118 sid: SessionId,
120 },
121}
122
123#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
125pub enum Fault {
126 TypeViolation {
128 expected: ValType,
130 actual: ValType,
132 message: String,
134 },
135 UnknownLabel {
137 label: String,
139 },
140 ChannelClosed {
142 endpoint: Endpoint,
144 },
145 InvalidSignature {
147 edge: Edge,
149 },
150 VerificationFailed {
152 edge: Edge,
154 message: String,
156 },
157 Invoke {
159 failure: crate::effect::EffectFailure,
161 },
162 Acquire {
164 layer: String,
166 failure: crate::effect::EffectFailure,
168 },
169 Transfer {
171 message: String,
173 },
174 Speculation {
176 message: String,
178 },
179 Close {
181 message: String,
183 },
184 FlowViolation {
186 message: String,
188 },
189 NoProgressToken {
191 edge: Edge,
193 },
194 OutputCondition {
196 predicate_ref: String,
198 },
199 OutOfRegisters,
201 PcOutOfBounds,
203 BufferFull {
205 endpoint: Endpoint,
207 },
208 OutOfCredits,
210}
211
212impl std::fmt::Display for Fault {
213 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214 match self {
215 Self::TypeViolation {
216 expected,
217 actual,
218 message,
219 } => write!(
220 f,
221 "type violation (expected {expected:?}, actual {actual:?}): {message}"
222 ),
223 Self::UnknownLabel { label } => write!(f, "unknown label: {label}"),
224 Self::ChannelClosed { endpoint } => {
225 write!(f, "channel closed: {}:{}", endpoint.sid, endpoint.role)
226 }
227 Self::InvalidSignature { edge } => write!(
228 f,
229 "invalid signature on edge {}:{}→{}",
230 edge.sid, edge.sender, edge.receiver
231 ),
232 Self::VerificationFailed { edge, message } => write!(
233 f,
234 "verification failed on edge {}:{}→{}: {message}",
235 edge.sid, edge.sender, edge.receiver
236 ),
237 Self::Invoke { failure } => write!(f, "invoke fault: {failure}"),
238 Self::Acquire { layer, failure } => {
239 write!(f, "acquire fault ({layer}): {failure}")
240 }
241 Self::Transfer { message } => write!(f, "transfer fault: {message}"),
242 Self::Speculation { message } => write!(f, "speculation fault: {message}"),
243 Self::Close { message } => write!(f, "close fault: {message}"),
244 Self::FlowViolation { message } => write!(f, "flow violation: {message}"),
245 Self::NoProgressToken { edge } => write!(
246 f,
247 "missing progress token for edge {}:{}→{}",
248 edge.sid, edge.sender, edge.receiver
249 ),
250 Self::OutputCondition { predicate_ref } => {
251 write!(f, "output-condition rejected: {predicate_ref}")
252 }
253 Self::OutOfRegisters => write!(f, "out of registers"),
254 Self::PcOutOfBounds => write!(f, "PC out of bounds"),
255 Self::BufferFull { endpoint } => {
256 write!(f, "buffer full: {}:{}", endpoint.sid, endpoint.role)
257 }
258 Self::OutOfCredits => write!(f, "out of credits"),
259 }
260 }
261}
262
263#[derive(Debug, Clone, Serialize, Deserialize)]
265pub struct Coroutine<E = ()> {
266 pub id: usize,
268 pub program_id: usize,
270 pub pc: PC,
272 pub regs: RegFile,
274 pub status: CoroStatus,
276 #[serde(default)]
278 pub effect_ctx: EffectCtx<E>,
279 pub owned_endpoints: Vec<Endpoint>,
281 pub progress_tokens: Vec<ProgressToken>,
283 pub knowledge_set: KnowledgeSet,
285 pub spec_state: Option<SpeculationState>,
287 pub session_id: SessionId,
289 pub role: String,
291 #[serde(default = "default_cost_budget")]
293 pub cost_budget: usize,
294}
295
296pub type CoroutineState<E = ()> = Coroutine<E>;
298
299#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
301pub struct KnowledgeFact {
302 pub endpoint: Endpoint,
304 pub fact: String,
306}
307
308pub type KnowledgeSet = Vec<KnowledgeFact>;
310
311#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
313pub struct SpeculationState {
314 pub ghost_sid: usize,
316 pub depth: usize,
318}
319
320impl Coroutine {
321 #[must_use]
323 pub fn new(
324 id: usize,
325 program_id: usize,
326 session_id: SessionId,
327 role: String,
328 num_regs: u16,
329 cost_budget: usize,
330 ) -> Self {
331 Self {
332 id,
333 program_id,
334 pc: 0,
335 regs: vec![Value::Unit; usize::from(num_regs)],
336 status: CoroStatus::Ready,
337 effect_ctx: EffectCtx::default(),
338 owned_endpoints: Vec::with_capacity(1),
339 progress_tokens: Vec::with_capacity(1),
340 knowledge_set: Vec::with_capacity(1),
341 spec_state: None,
342 session_id,
343 role,
344 cost_budget,
345 }
346 }
347
348 #[must_use]
350 pub fn is_ready(&self) -> bool {
351 self.status == CoroStatus::Ready
352 }
353
354 #[must_use]
356 pub fn is_terminal(&self) -> bool {
357 matches!(self.status, CoroStatus::Done | CoroStatus::Faulted(_))
358 }
359}
360
361impl Fault {
362 #[must_use]
364 pub fn type_violation(message: impl Into<String>) -> Self {
365 Self::TypeViolation {
366 expected: ValType::Unit,
367 actual: ValType::Unit,
368 message: message.into(),
369 }
370 }
371}