Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
promise.qc
Go to the documentation of this file.
1#include "promise.qh"
2
4.void(entity this) _ref_finalize;
5
6void ref_init(entity this, int init, void(entity this) finalize)
7{
8 this._ref_count = init;
9 this._ref_finalize = finalize;
10}
11
12// todo: rename to `ref`
14{
15 ++this._ref_count;
16 return this;
17}
18
19entity unref(Promise this)
20{
21 --this._ref_count;
22 if (!this._ref_count)
23 {
24 LOG_DEBUGF("Finalize entity %i (from %s)", this, this.sourceLoc);
25 this._ref_finalize(this);
26 return NULL;
27 }
28 return this;
29}
30
31enum
32{
36};
37
38classfield(Promise) .int _promise_state;
39classfield(Promise) .entity _promise_result;
40classfield(Promise) .IntrusiveList _promise_handlers;
41
42entityclass(PromiseHandler);
43classfield(PromiseHandler) .Promise _promise_handler_ret;
44classfield(PromiseHandler) .entity _promise_handler_data;
45classfield(PromiseHandler) .Promise(Promise ret, entity result, entity userdata) _promise_handler_resolve;
46classfield(PromiseHandler) .Promise(Promise ret, entity err, entity userdata) _promise_handler_reject;
47
48void _Promise_finalize(Promise this)
49{
50 delete(this);
51}
52
53Promise Promise_new_(Promise this)
54{
56 this._promise_result = this; // promises default to being their own result to save on entities
57 return this;
58}
59
60void _Promise_handle(Promise this, PromiseHandler h);
61
62void Promise_resolve(Promise this)
63{
64 if (!this)
65 {
66 LOG_SEVERE("Attempted to resolve a null promise");
67 return;
68 }
69 if (this._promise_state != PROMISE_PENDING)
70 {
71 LOG_SEVEREF("Resolved non-pending promise %i", this);
72 return;
73 }
74 this._promise_state = PROMISE_RESOLVED;
75 if (this._promise_handlers)
76 {
77 IL_EACH(this._promise_handlers, true, _Promise_handle(this, it));
78 IL_DELETE(this._promise_handlers);
79 }
80 unref(this);
81 return;
82}
83
84void Promise_reject(Promise this)
85{
86 if (!this)
87 {
88 LOG_SEVERE("Attempted to reject a null promise");
89 return;
90 }
91 if (this._promise_state != PROMISE_PENDING)
92 {
93 LOG_SEVEREF("Rejected non-pending promise %i", this);
94 return;
95 }
96 this._promise_state = PROMISE_REJECTED;
97 if (this._promise_handlers)
98 {
99 IL_EACH(this._promise_handlers, true, _Promise_handle(this, it));
100 IL_DELETE(this._promise_handlers);
101 }
102 unref(this);
103 return;
104}
105
106Promise _Promise_then(Promise this, Promise ret,
107 Promise(Promise ret, entity result, entity userdata) onResolve,
108 Promise(Promise ret, entity result, entity userdata) onReject,
109 entity userdata
110);
111
112void _Promise_handle(Promise this, PromiseHandler h)
113{
114 switch (this._promise_state)
115 {
116 case PROMISE_PENDING:
117 if (!this._promise_handlers)
118 this._promise_handlers = IL_NEW();
119 IL_PUSH(this._promise_handlers, h);
120 break;
121 case PROMISE_RESOLVED:
122 {
123 Promise ret = h._promise_handler_ret;
124 Promise p = h._promise_handler_resolve(ret, this._promise_result, h._promise_handler_data);
125 if (p != ret)
126 _Promise_then(p, ret, func_null, func_null, NULL); // bind p -> ret
127 delete(h);
128 break;
129 }
130 case PROMISE_REJECTED:
131 {
132 Promise ret = h._promise_handler_ret;
133 Promise p = h._promise_handler_reject(ret, this._promise_result, h._promise_handler_data);
134 if (p != ret)
135 _Promise_then(p, ret, func_null, func_null, NULL); // bind p -> ret
136 delete(h);
137 break;
138 }
139 }
140}
141
142void _Promise_done(Promise this, Promise ret,
143 Promise(Promise ret, entity result, entity userdata) onResolve,
144 Promise(Promise ret, entity err, entity userdata) onReject,
145 entity userdata)
146{
147 PromiseHandler h = new_pure(PromiseHandler);
148 h._promise_handler_ret = ret;
149 h._promise_handler_data = userdata;
150 h._promise_handler_resolve = onResolve;
151 h._promise_handler_reject = onReject;
152 _Promise_handle(this, h);
153}
154
155Promise _Promise_onResolve_default(Promise ret, entity result, entity userdata)
156{
157 ret._promise_result = result;
158 Promise_resolve(ret);
159 return ret;
160}
161
162Promise _Promise_onReject_default(Promise ret, entity err, entity userdata)
163{
164 ret._promise_result = err;
165 Promise_reject(ret);
166 return ret;
167}
168
169Promise _Promise_then(Promise this, Promise ret,
170 Promise(Promise ret, entity result, entity userdata) onResolve,
171 Promise(Promise ret, entity result, entity userdata) onReject,
172 entity userdata)
173{
174 _Promise_done(this, ret,
175 (onResolve ? onResolve : _Promise_onResolve_default),
176 (onReject ? onReject : _Promise_onReject_default),
177 userdata
178 );
179 return ret;
180}
181
182Promise Promise_then_(Promise this, Promise ret,
183 Promise(Promise ret, entity result, entity userdata) onResolve,
184 entity userdata)
185{
186 unref(ret); // ret is a temporary
187 return _Promise_then(this, ret, onResolve, func_null, userdata);
188}
189
190Promise Promise_catch_(Promise this, Promise ret,
191 Promise(Promise ret, entity result, entity userdata) onReject,
192 entity userdata)
193{
194 unref(ret); // ret is a temporary
195 return _Promise_then(this, ret, func_null, onReject, userdata);
196}
197
198// utils
199
200#ifndef MENUQC
201
202Promise Promise_sleep(float n)
203{
204 Promise p = unref(Promise_new());
206 p.nextthink = time + n;
207 return p;
208}
209
210#endif
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float time
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define IL_NEW()
#define IL_EACH(this, cond, body)
#define IL_DELETE(this)
Delete the list.
#define LOG_SEVEREF(...)
Definition log.qh:55
#define LOG_SEVERE(...)
Definition log.qh:54
#define LOG_DEBUGF(...)
Definition log.qh:79
var void func_null()
#define entityclass(...)
Definition oo.qh:51
#define new_pure(class)
purely logical entities (not linked to the area grid)
Definition oo.qh:66
#define classfield(name)
Definition oo.qh:56
string sourceLoc
Location entity was spawned from in source.
Definition oo.qh:27
#define NULL
Definition post.qh:14
@ PROMISE_RESOLVED
Definition promise.qc:34
@ PROMISE_PENDING
Definition promise.qc:33
@ PROMISE_REJECTED
Definition promise.qc:35
entity result
Definition promise.qc:45
Promise Promise_catch_(Promise this, Promise ret, Promise(Promise ret, entity result, entity userdata) onReject, entity userdata)
Definition promise.qc:190
void ref_init(entity this, int init, void(entity this) finalize)
Definition promise.qc:6
entity REF(entity this)
Definition promise.qc:13
void _Promise_handle(Promise this, PromiseHandler h)
Definition promise.qc:112
Promise _Promise_onResolve_default(Promise ret, entity result, entity userdata)
Definition promise.qc:155
Promise _Promise_onReject_default(Promise ret, entity err, entity userdata)
Definition promise.qc:162
void _Promise_finalize(Promise this)
Definition promise.qc:48
entity unref(Promise this)
Definition promise.qc:19
entity err
Definition promise.qc:46
Promise Promise_then_(Promise this, Promise ret, Promise(Promise ret, entity result, entity userdata) onResolve, entity userdata)
Definition promise.qc:182
int _ref_count
Definition promise.qc:3
entity entity userdata _promise_handler_reject
Definition promise.qc:46
void _Promise_done(Promise this, Promise ret, Promise(Promise ret, entity result, entity userdata) onResolve, Promise(Promise ret, entity err, entity userdata) onReject, entity userdata)
Definition promise.qc:142
void Promise_resolve(Promise this)
Notify all Promise_then subscribers that this promise has resolved.
Definition promise.qc:62
entity entity userdata _promise_handler_resolve
Definition promise.qc:45
Promise Promise_new_(Promise this)
Definition promise.qc:53
void Promise_reject(Promise this)
Notify all Promise_catch subscribers that this promise has rejected.
Definition promise.qc:84
Promise _Promise_then(Promise this, Promise ret, Promise(Promise ret, entity result, entity userdata) onResolve, Promise(Promise ret, entity result, entity userdata) onReject, entity userdata)
Definition promise.qc:169
#define Promise_new()
Definition promise.qh:5
#define setthink(e, f)