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