active_rpc/promise.rs
1//! Promises: results that exist before they are ready.
2//!
3//! A promise is a slot the kernel fills later. Passing one as an argument makes
4//! a call *pipelined*: the kernel keeps the dependent call at the provider and
5//! dispatches it in the same batch that resolves the promise, so a chain costs
6//! one provider round-trip instead of one per step (spec §5).
7//!
8//! A promise can be resolved once, rejected once, or cancelled; every state
9//! transition is checked, and awaiting a cancelled promise is an error rather
10//! than a hang.
11
12use std::fmt;
13
14use crate::error::{Error, Result};
15use crate::value::Value;
16
17/// Identity of a promise inside one kernel.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
19pub struct PromiseId(pub u64);
20
21impl fmt::Display for PromiseId {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 write!(f, "p{}", self.0)
24 }
25}
26
27/// Lifecycle of a promise.
28#[derive(Debug, Clone, PartialEq)]
29pub enum PromiseState {
30 /// Waiting for its producing call.
31 Pending,
32 /// Resolved with a value.
33 Resolved(Value),
34 /// Failed; the original error is preserved so the class survives the hop.
35 Rejected(crate::error::Error),
36 /// Cancelled by the caller; never resolves.
37 Cancelled,
38}
39
40impl PromiseState {
41 /// Whether the promise has resolved, failed or been cancelled.
42 pub fn is_settled(&self) -> bool {
43 !matches!(self, PromiseState::Pending)
44 }
45}
46
47/// Provider-side record of one promise.
48#[derive(Debug, Clone, PartialEq)]
49pub struct PromiseRecord {
50 /// Kernel-assigned identifier.
51 pub id: PromiseId,
52 /// Current state (pending until the producing call settles).
53 pub state: PromiseState,
54 /// Calls waiting on this promise (derived, informational).
55 pub waiters: u32,
56 /// Lane that issued the producing call.
57 pub lane: u64,
58 /// Live [`crate::kernel::PromiseHandle`]s referencing this record.
59 ///
60 /// A settled record with a live handle is never evicted by retention
61 /// trimming: the caller can still read it. `Agent::call` sets this to one
62 /// when it returns the handle.
63 pub handles: u32,
64}
65
66impl PromiseRecord {
67 /// Create a pending record for `id`, owned by `lane`.
68 pub fn new(id: PromiseId, lane: u64) -> Self {
69 Self {
70 id,
71 state: PromiseState::Pending,
72 waiters: 0,
73 lane,
74 // No handle owns a reference until `Agent::call` builds one.
75 handles: 0,
76 }
77 }
78
79 /// Resolve once.
80 pub fn resolve(&mut self, value: Value) -> Result<()> {
81 match self.state {
82 PromiseState::Pending => {
83 self.state = PromiseState::Resolved(value);
84 Ok(())
85 }
86 _ => Err(Error::PromiseAlreadyResolved(self.id.0)),
87 }
88 }
89
90 /// Reject once.
91 pub fn reject(&mut self, error: crate::error::Error) -> Result<()> {
92 match self.state {
93 PromiseState::Pending => {
94 self.state = PromiseState::Rejected(error);
95 Ok(())
96 }
97 _ => Err(Error::PromiseAlreadyResolved(self.id.0)),
98 }
99 }
100
101 /// Cancel a pending promise.
102 pub fn cancel(&mut self) -> Result<()> {
103 match self.state {
104 PromiseState::Pending => {
105 self.state = PromiseState::Cancelled;
106 Ok(())
107 }
108 _ => Err(Error::PromiseAlreadyResolved(self.id.0)),
109 }
110 }
111
112 /// The settled value, or an error describing why it is not available.
113 pub fn value(&self) -> Result<Value> {
114 match &self.state {
115 PromiseState::Resolved(value) => Ok(value.clone()),
116 PromiseState::Pending => Err(Error::UnresolvablePromise(self.id.0)),
117 PromiseState::Rejected(error) => Err(error.clone()),
118 PromiseState::Cancelled => Err(Error::PromiseCancelled(self.id.0)),
119 }
120 }
121}