// Copyright (c) 2025 TerraByte Inc. // // The concrete implementation of the IPromise interface. // It manages the state and execution of an asynchronous operation. using System; using System.Threading; using UnityEngine.Scripting; namespace Terra.Arbitrator.Promises { [Preserve] public class Promise : IPromise, ITrackablePromise { private PromiseState State { get; set; } private TResult _resolvedValue; private Exception _rejectedException; private Action _onResolvedCallback; private Action _onRejectedCallback; private Action _onFinallyCallback; private volatile bool _isResolved; private volatile bool _isRejected; /// /// Creates a new promise and starts its execution on a background thread. /// /// The function to execute, which takes resolve and reject actions. public Promise(Action, Action> executor) { _isRejected = false; State = PromiseState.Pending; // The manager will track this promise until it's settled. PromiseManager.Track(this); ThreadPool.QueueUserWorkItem(_ => { try { executor(Resolve, Reject); } catch (Exception ex) { Reject(ex); } }); } private void Resolve(TResult value) { if (State != PromiseState.Pending) return; _resolvedValue = value; State = PromiseState.Resolved; _isResolved = true; // Signal that we are done } private void Reject(Exception ex) { if (State != PromiseState.Pending) return; _rejectedException = ex; State = PromiseState.Rejected; _isRejected = true; // Signal that we are done } public IPromise Then(Action onResolved) { _onResolvedCallback = onResolved; return this; } public IPromise Then(Func> onResolved) { return new Promise(LocalExecutor); void LocalExecutor(Action resolve, Action reject) { Then(OnResolved).Catch(reject); return; void OnResolved(TResult result) { try { var nextPromise = onResolved(result); nextPromise.Then(resolve).Catch(reject); } catch (Exception ex) { reject(ex); } } } } public IPromise Catch(Action onRejected) { _onRejectedCallback = onRejected; return this; } public void Finally(Action onFinally) { _onFinallyCallback = onFinally; } /// /// Called by the PromiseManager from the main thread to execute callbacks. /// /// True if the promise is settled, otherwise false. public bool Tick() { if (_isResolved) { try { _onResolvedCallback?.Invoke(_resolvedValue); } finally { _onFinallyCallback?.Invoke(); } return true; } if (_isRejected) { try { _onRejectedCallback?.Invoke(_rejectedException); } finally { _onFinallyCallback?.Invoke(); } return true; } return false; } } }