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}
59
60impl PromiseRecord {
61    /// Create a pending record for `id`, owned by `lane`.
62    pub fn new(id: PromiseId, lane: u64) -> Self {
63        Self {
64            id,
65            state: PromiseState::Pending,
66            waiters: 0,
67            lane,
68        }
69    }
70
71    /// Resolve once.
72    pub fn resolve(&mut self, value: Value) -> Result<()> {
73        match self.state {
74            PromiseState::Pending => {
75                self.state = PromiseState::Resolved(value);
76                Ok(())
77            }
78            _ => Err(Error::PromiseAlreadyResolved(self.id.0)),
79        }
80    }
81
82    /// Reject once.
83    pub fn reject(&mut self, error: crate::error::Error) -> Result<()> {
84        match self.state {
85            PromiseState::Pending => {
86                self.state = PromiseState::Rejected(error);
87                Ok(())
88            }
89            _ => Err(Error::PromiseAlreadyResolved(self.id.0)),
90        }
91    }
92
93    /// Cancel a pending promise.
94    pub fn cancel(&mut self) -> Result<()> {
95        match self.state {
96            PromiseState::Pending => {
97                self.state = PromiseState::Cancelled;
98                Ok(())
99            }
100            _ => Err(Error::PromiseAlreadyResolved(self.id.0)),
101        }
102    }
103
104    /// The settled value, or an error describing why it is not available.
105    pub fn value(&self) -> Result<Value> {
106        match &self.state {
107            PromiseState::Resolved(value) => Ok(value.clone()),
108            PromiseState::Pending => Err(Error::UnresolvablePromise(self.id.0)),
109            PromiseState::Rejected(error) => Err(error.clone()),
110            PromiseState::Cancelled => Err(Error::PromiseCancelled(self.id.0)),
111        }
112    }
113}