swan_core/value/promise.rs
1//! Single-assignment promises for Swan.
2//!
3//! A [`Promise`] is a shared, mutable cell that is either *pending* or
4//! *resolved* with a [`Value`]. Callbacks registered with [`Promise::then`]
5//! (or [`Promise::then_apply`]) run when the promise resolves and produce a
6//! new child promise holding the callback's result, so promises form a chain.
7//!
8//! Semantics:
9//! - **Resolve once.** The first call to [`Promise::resolve`] wins; later calls
10//! are ignored.
11//! - **Never rejects.** There is no failure state. Resolving with
12//! `Value::Undefined(_)` stores `Value::Nothing` instead.
13//! - **Synchronous dispatch.** Callbacks run immediately on the caller's stack,
14//! either inside `resolve` (if registered while pending) or inside `then`
15//! (if the promise is already resolved). There is no event loop or scheduler
16//! in this module.
17//! - **Shared identity.** Cloning a `Promise` clones the `Rc` handle, not the
18//! state; all clones observe the same resolution.
19//! - **No flattening.** If a callback returns a `Value::Promise`, the child
20//! resolves to that promise value; it is not unwrapped.
21
22use std::cell::RefCell;
23use std::fmt;
24use std::rc::Rc;
25use crate::value::Value;
26use crate::evaluator::eval_apply;
27
28/// A Rust callback queued on a pending promise.
29///
30/// It receives the parent's resolved value and returns the value that will
31/// resolve the corresponding child promise.
32pub type PromiseCallback = Rc<dyn Fn(Value) -> Value>;
33
34/// The shared state of a [`Promise`], kept behind `Rc<RefCell<..>>`.
35#[derive(Clone)]
36pub struct PromiseData {
37 /// `None` while pending; `Some(v)` once resolved. Set at most once and
38 /// never `Value::Undefined`.
39 pub value: Option<Value>,
40
41 /// Callbacks waiting for resolution, each paired with the child
42 /// `Value::Promise` to resolve with that callback's result. Always empty
43 /// once the promise is resolved (drained by [`Promise::resolve`]).
44 pub children: Vec<(PromiseCallback, Value)>,
45}
46
47/// Prints the resolved value (if any) and only the *number* of queued
48/// children, since callbacks are opaque closures and cannot be displayed.
49impl fmt::Debug for PromiseData {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 f.debug_struct("PromiseData")
52 .field("value", &self.value)
53 .field("children_count", &self.children.len())
54 .finish()
55 }
56}
57
58/// A single-assignment value that may not be available yet.
59///
60/// A promise is *pending* until [`Promise::resolve`] gives it a value, and
61/// *resolved* afterwards. Callbacks registered with [`Promise::then`] run when
62/// it resolves.
63///
64/// - **Resolve once.** The first call to `resolve` wins; later calls are
65/// ignored.
66/// - **Never rejects.** There is no failure state. Resolving with
67/// [`Value::Undefined`] stores [`Value::Nothing`] instead.
68/// - **Synchronous dispatch.** Callbacks run on the caller's stack, inside
69/// `resolve` (if registered while pending) or inside `then` (if already
70/// resolved). There is no scheduler in this crate.
71/// - **Shared identity.** `Promise` is a cheap handle: clones observe the same
72/// resolution.
73/// - **No flattening.** If a callback returns a `Value::Promise`, the child
74/// promise resolves to that promise; it is not unwrapped.
75///
76/// The inner `Rc<RefCell<PromiseData>>` is public so that hosts can inspect
77/// the state; prefer `then` and `resolve` to change it.
78///
79/// # Examples
80///
81/// ```
82/// use swan_core::value::{Promise, Value};
83///
84/// let p = Promise::new();
85/// let child = p.then(|v| match v {
86/// Value::Numb(n) => Value::Numb(n + 1.0),
87/// other => other,
88/// });
89/// p.resolve(Value::Numb(41.0));
90///
91/// if let Value::Promise(child) = child {
92/// assert_eq!(child.0.borrow().value, Some(Value::Numb(42.0)));
93/// }
94/// ```
95#[derive(Clone, Debug)]
96pub struct Promise(pub Rc<RefCell<PromiseData>>);
97
98impl Promise {
99 /// Creates a new pending promise with no value and no queued callbacks.
100 pub fn new() -> Self {
101 Self(Rc::new(RefCell::new(PromiseData {
102 value: None,
103 children: Vec::new(),
104 })))
105 }
106
107 /// Registers a Rust callback and returns a child promise (as `Value::Promise`)
108 /// that resolves to the callback's result.
109 ///
110 /// - If `self` is already resolved, `f` is called immediately with a clone of
111 /// the value and the returned child is already resolved.
112 /// - If `self` is pending, `f` is queued and runs when `self` is resolved.
113 ///
114 /// `f` is invoked at most once. If `f` returns `Value::Undefined`, the child
115 /// resolves to `Value::Nothing` (see [`Promise::resolve`]).
116 pub fn then(&self, f: impl Fn(Value) -> Value + 'static) -> Value {
117 let callback: PromiseCallback = Rc::new(f);
118 let child = Promise::new();
119 let child_val = Value::Promise(child.clone());
120
121 let resolved = self.0.borrow().value.clone();
122 match resolved {
123 Some(v) => child.resolve(callback(v)),
124 None => self.0.borrow_mut().children.push((callback, child_val.clone())),
125 }
126
127 child_val
128 }
129
130 /// Like [`Promise::then`], but takes a Swan callable instead of a Rust closure.
131 ///
132 /// The callable `f` is applied to the resolved value via
133 /// [`eval_apply`], with `pos` as the source position used in any resulting
134 /// `Undefined` (for example, when `f` is not callable). Such an `Undefined`
135 /// result resolves the child to `Value::Nothing`.
136 pub fn then_apply(&self, f: Value, pos: usize) -> Value {
137 self.then(move |v| eval_apply(f.clone(), v, pos))
138 }
139
140 /// Resolves this promise with `v` and runs all queued callbacks.
141 ///
142 /// - Only the first call has any effect; if the promise is already resolved,
143 /// `v` is ignored and nothing runs.
144 /// - `Value::Undefined(_)` is replaced by `Value::Nothing`, so a promise never
145 /// holds an undefined value.
146 /// - Each queued callback is called in registration order with a clone of the
147 /// resolved value, and its result resolves the associated child promise.
148 /// Resolution therefore cascades down the chain synchronously.
149 /// - The internal borrow is released before callbacks run, so callbacks may
150 /// safely call `then` on this promise (they will see it already resolved).
151 pub fn resolve(&self, v: Value) {
152 let mut inner = self.0.borrow_mut();
153
154 // Promises resolve only once
155 if inner.value.is_some() {
156 return;
157 }
158
159 // A swan promise never rejects; undefined values resolve to Nothing
160 let resolve_val = if matches!(v, Value::Undefined(_)) {
161 Value::Nothing
162 } else {
163 v
164 };
165
166 inner.value = Some(resolve_val.clone());
167
168 // Drain children to drop mutable borrow on inner before invoking closures
169 let children = std::mem::take(&mut inner.children);
170 drop(inner);
171
172 for (f, child_val) in children {
173 let res = f(resolve_val.clone());
174 if let Value::Promise(child) = child_val {
175 child.resolve(res);
176 }
177 }
178 }
179}