Skip to main content

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}