MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1#include <stdlib.h>
2#include <string.h>
3
4#include "ant.h"
5#include "errors.h"
6#include "runtime.h"
7#include "internal.h"
8#include "descriptors.h"
9
10#include "gc/roots.h"
11#include "silver/engine.h"
12#include "modules/assert.h"
13#include "modules/symbol.h"
14#include "streams/transform.h"
15#include "streams/readable.h"
16#include "streams/writable.h"
17
18ant_value_t g_ts_proto;
19ant_value_t g_ts_ctrl_proto;
20
21static inline bool ts_has_stream_shape(ant_value_t obj) {
22 return vtype(js_get_slot(obj, SLOT_DATA)) == T_NUM
23 && rs_is_stream(js_get_slot(obj, SLOT_ENTRIES))
24 && ws_is_stream(js_get_slot(obj, SLOT_CTOR));
25}
26
27static inline bool ts_has_controller_shape(ant_value_t obj) {
28 ant_value_t ts_obj = js_get_slot(obj, SLOT_DATA);
29 return is_object_type(ts_obj)
30 && js_check_brand(ts_obj, BRAND_TRANSFORM_STREAM)
31 && vtype(js_get_slot(ts_obj, SLOT_DATA)) == T_NUM
32 && js_get_slot(ts_obj, SLOT_DEFAULT) == obj;
33}
34
35bool ts_is_controller(ant_value_t obj) {
36 return js_check_brand(obj, BRAND_TRANSFORM_STREAM_CONTROLLER)
37 && ts_has_controller_shape(obj);
38}
39
40bool ts_is_stream(ant_value_t obj) {
41 ant_value_t ctrl_obj = js_get_slot(obj, SLOT_DEFAULT);
42 return js_check_brand(obj, BRAND_TRANSFORM_STREAM)
43 && ts_has_stream_shape(obj)
44 && js_check_brand(ctrl_obj, BRAND_TRANSFORM_STREAM_CONTROLLER)
45 && ts_has_controller_shape(ctrl_obj);
46}
47
48ant_value_t ts_stream_readable(ant_value_t ts_obj) {
49 return js_get_slot(ts_obj, SLOT_ENTRIES);
50}
51
52ant_value_t ts_stream_writable(ant_value_t ts_obj) {
53 return js_get_slot(ts_obj, SLOT_CTOR);
54}
55
56static void ts_ws_finalize(ant_t *js, ant_object_t *obj) {
57 if (!obj->extra_slots) return;
58 ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots;
59 for (uint8_t i = 0; i < obj->extra_count; i++) {
60 if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) {
61 free((ws_stream_t *)(uintptr_t)(size_t)js_getnum(entries[i].value));
62 return;
63 }}
64}
65
66static void ts_ws_ctrl_finalize(ant_t *js, ant_object_t *obj) {
67 if (!obj->extra_slots) return;
68 ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots;
69 for (uint8_t i = 0; i < obj->extra_count; i++) {
70 if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) {
71 ws_controller_t *ctrl = (ws_controller_t *)(uintptr_t)(size_t)js_getnum(entries[i].value);
72 free(ctrl->queue_sizes);
73 free(ctrl);
74 return;
75 }}
76}
77
78static void ts_rs_finalize(ant_t *js, ant_object_t *obj) {
79 if (!obj->extra_slots) return;
80 ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots;
81 for (uint8_t i = 0; i < obj->extra_count; i++) {
82 if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) {
83 free((rs_stream_t *)(uintptr_t)(size_t)js_getnum(entries[i].value));
84 return;
85 }}
86}
87
88static void ts_rs_ctrl_finalize(ant_t *js, ant_object_t *obj) {
89 if (!obj->extra_slots) return;
90 ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots;
91 for (uint8_t i = 0; i < obj->extra_count; i++) {
92 if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) {
93 rs_controller_t *ctrl = (rs_controller_t *)(uintptr_t)(size_t)js_getnum(entries[i].value);
94 free(ctrl->queue_sizes);
95 free(ctrl);
96 return;
97 }}
98}
99
100static inline bool ts_get_backpressure(ant_value_t ts_obj) {
101 return js_getnum(js_get_slot(ts_obj, SLOT_DATA)) != 0;
102}
103
104static inline void ts_set_bp_flag(ant_value_t ts_obj, bool bp) {
105 js_set_slot(ts_obj, SLOT_DATA, js_mknum(bp ? 1 : 0));
106}
107
108static inline ant_value_t ts_readable(ant_value_t ts_obj) {
109 return ts_stream_readable(ts_obj);
110}
111
112static inline ant_value_t ts_writable(ant_value_t ts_obj) {
113 return ts_stream_writable(ts_obj);
114}
115
116static inline ant_value_t ts_bp_promise(ant_value_t ts_obj) {
117 return js_get_slot(ts_obj, SLOT_AUX);
118}
119
120ant_value_t ts_stream_controller(ant_value_t ts_obj) {
121 return js_get_slot(ts_obj, SLOT_DEFAULT);
122}
123
124static inline ant_value_t ts_controller(ant_value_t ts_obj) {
125 return ts_stream_controller(ts_obj);
126}
127
128static inline ant_value_t ts_ctrl_transform_fn(ant_value_t ctrl_obj) {
129 return js_get_slot(ctrl_obj, SLOT_ENTRIES);
130}
131
132static inline ant_value_t ts_ctrl_flush_fn(ant_value_t ctrl_obj) {
133 return js_get_slot(ctrl_obj, SLOT_CTOR);
134}
135
136static inline ant_value_t ts_ctrl_cancel_fn(ant_value_t ctrl_obj) {
137 return js_get_slot(ctrl_obj, SLOT_AUX);
138}
139
140static inline ant_value_t ts_ctrl_transformer(ant_value_t ctrl_obj) {
141 return js_get_slot(ctrl_obj, SLOT_SETTLED);
142}
143
144static inline ant_value_t ts_ctrl_stream(ant_value_t ctrl_obj) {
145 return js_get_slot(ctrl_obj, SLOT_DATA);
146}
147
148static inline ant_value_t ts_ctrl_finish_promise(ant_value_t ctrl_obj) {
149 return js_get_slot(ctrl_obj, SLOT_RS_PULL);
150}
151
152static inline ant_value_t ts_writable_stored_error(ant_value_t ts_obj) {
153 return js_get_slot(ts_writable(ts_obj), SLOT_AUX);
154}
155
156static inline ant_value_t ts_cancel_promise(ant_value_t ts_obj) {
157 return js_get_slot(ts_obj, SLOT_RS_CANCEL);
158}
159
160static inline bool ts_cancel_started_by_abort(ant_value_t ts_obj) {
161 return js_get_slot(ts_obj, SLOT_WS_ABORT) == js_true;
162}
163
164static inline bool ts_is_flushing(ant_value_t ts_obj) {
165 return js_get_slot(ts_obj, SLOT_WS_CLOSE) == js_true;
166}
167
168static inline ant_value_t ts_cancel_settle_error(ant_value_t ts_obj) {
169 return js_get_slot(ts_obj, SLOT_RS_SIZE);
170}
171
172static inline bool ts_cancel_joined_abort(ant_value_t ts_obj) {
173 return js_get_slot(ts_obj, SLOT_WS_WRITE) == js_true;
174}
175
176static inline bool ts_cancel_has_user_handler(ant_value_t ts_obj) {
177 return js_get_slot(ts_obj, SLOT_WS_SIGNAL) == js_true;
178}
179
180static inline void ts_set_flushing(ant_value_t ts_obj, bool flushing) {
181 js_set_slot(ts_obj, SLOT_WS_CLOSE, flushing ? js_true : js_false);
182}
183
184static inline void ts_set_cancel_state(ant_t *js, ant_value_t ts_obj, ant_value_t promise, bool started_by_abort, bool has_user_handler) {
185 js_set_slot_wb(js, ts_obj, SLOT_RS_CANCEL, promise);
186 js_set_slot(ts_obj, SLOT_WS_ABORT, started_by_abort ? js_true : js_false);
187 js_set_slot(ts_obj, SLOT_RS_SIZE, js_mkundef());
188 js_set_slot(ts_obj, SLOT_WS_WRITE, js_false);
189 js_set_slot(ts_obj, SLOT_WS_SIGNAL, has_user_handler ? js_true : js_false);
190}
191
192static inline void ts_clear_cancel_state(ant_value_t ts_obj, ant_value_t promise) {
193if (ts_cancel_promise(ts_obj) == promise) {
194 js_set_slot(ts_obj, SLOT_RS_CANCEL, js_mkundef());
195 js_set_slot(ts_obj, SLOT_WS_ABORT, js_false);
196 js_set_slot(ts_obj, SLOT_WS_SIGNAL, js_false);
197}}
198
199static void ts_ctrl_clear_algorithms(ant_value_t ctrl_obj) {
200 js_set_slot(ctrl_obj, SLOT_ENTRIES, js_mkundef());
201 js_set_slot(ctrl_obj, SLOT_CTOR, js_mkundef());
202 js_set_slot(ctrl_obj, SLOT_AUX, js_mkundef());
203}
204
205static ant_value_t ts_take_thrown_or(ant_t *js, ant_value_t fallback) {
206 ant_value_t thrown = js->thrown_exists ? js->thrown_value : js_mkundef();
207 ant_value_t err = is_object_type(thrown) ? thrown : fallback;
208 js->thrown_exists = false;
209 js->thrown_value = js_mkundef();
210 js->thrown_stack = js_mkundef();
211 return err;
212}
213
214static void ts_chain_promise(ant_t *js, ant_value_t val, ant_value_t res_fn, ant_value_t rej_fn) {
215 GC_ROOT_SAVE(root_mark, js);
216 GC_ROOT_PIN(js, val);
217 GC_ROOT_PIN(js, res_fn);
218 GC_ROOT_PIN(js, rej_fn);
219
220 ant_value_t promise = val;
221 GC_ROOT_PIN(js, promise);
222 if (vtype(promise) != T_PROMISE) {
223 promise = js_mkpromise(js);
224 GC_ROOT_PIN(js, promise);
225 js_resolve_promise(js, promise, val);
226 }
227
228 ant_value_t then_result = js_promise_then(js, promise, res_fn, rej_fn);
229 GC_ROOT_PIN(js, then_result);
230 promise_mark_handled(then_result);
231 GC_ROOT_RESTORE(js, root_mark);
232}
233
234static void ts_error(ant_t *js, ant_value_t ts_obj, ant_value_t e) {
235 ant_value_t readable = ts_readable(ts_obj);
236 ant_value_t rs_ctrl = rs_stream_controller(js, readable);
237 rs_controller_t *rc = rs_get_controller(rs_ctrl);
238 if (rc) {
239 rc->queue_total_size = 0;
240 rc->queue_sizes_len = 0;
241 rs_default_controller_clear_algorithms(rs_ctrl);
242 }
243 readable_stream_error(js, readable, e);
244
245 if (ts_get_backpressure(ts_obj)) {
246 ant_value_t bp = ts_bp_promise(ts_obj);
247 if (vtype(bp) == T_PROMISE) js_resolve_promise(js, bp, js_mkundef());
248 ts_set_bp_flag(ts_obj, false);
249 }
250}
251
252static void ts_error_writable_and_unblock_write(ant_t *js, ant_value_t ts_obj, ant_value_t e) {
253 ant_value_t ctrl_obj = ts_controller(ts_obj);
254 ts_ctrl_clear_algorithms(ctrl_obj);
255
256 ant_value_t writable = ts_writable(ts_obj);
257 ws_stream_t *ws = ws_get_stream(writable);
258 if (ws && ws->state == WS_STATE_WRITABLE)
259 ws_default_controller_error(js, ws_stream_controller(writable), e);
260
261 if (ts_get_backpressure(ts_obj)) {
262 ant_value_t bp = ts_bp_promise(ts_obj);
263 if (vtype(bp) == T_PROMISE) js_resolve_promise(js, bp, js_mkundef());
264 ts_set_bp_flag(ts_obj, false);
265 }
266}
267
268static void ts_set_backpressure(ant_t *js, ant_value_t ts_obj, bool backpressure) {
269 if (ts_get_backpressure(ts_obj)) {
270 ant_value_t bp = ts_bp_promise(ts_obj);
271 if (vtype(bp) == T_PROMISE) js_resolve_promise(js, bp, js_mkundef());
272 }
273 ant_value_t new_bp = js_mkpromise(js);
274 js_set_slot_wb(js, ts_obj, SLOT_AUX, new_bp);
275 ts_set_bp_flag(ts_obj, backpressure);
276}
277
278ant_value_t ts_ctrl_enqueue(ant_t *js, ant_value_t ctrl_obj, ant_value_t chunk) {
279 ant_value_t ts_obj = ts_ctrl_stream(ctrl_obj);
280 ant_value_t readable = ts_readable(ts_obj);
281 ant_value_t rs_ctrl = rs_stream_controller(js, readable);
282 rs_stream_t *rs = rs_get_stream(readable);
283
284 if (!rs || rs->state != RS_STATE_READABLE)
285 return js_mkerr_typed(js, JS_ERR_TYPE, "Readable side is not in a readable state");
286
287 ant_value_t enqueue_result = rs_controller_enqueue(js, rs_ctrl, chunk);
288 if (is_err(enqueue_result)) {
289 ant_value_t err = ts_take_thrown_or(js, enqueue_result);
290 ts_error_writable_and_unblock_write(js, ts_obj, err);
291 return js_throw(js, err);
292 }
293
294 rs_controller_t *rc = rs_get_controller(rs_ctrl);
295 bool bp = rc && ((rc->strategy_hwm - rc->queue_total_size) <= 0);
296 if (bp != ts_get_backpressure(ts_obj)) ts_set_backpressure(js, ts_obj, bp);
297
298 return js_mkundef();
299}
300
301void ts_ctrl_error(ant_t *js, ant_value_t ctrl_obj, ant_value_t e) {
302 ant_value_t ts_obj = ts_ctrl_stream(ctrl_obj);
303 if (vtype(ts_cancel_promise(ts_obj)) == T_PROMISE && ts_cancel_has_user_handler(ts_obj))
304 js_set_slot_wb(js, ts_obj, SLOT_RS_SIZE, e);
305 ts_error(js, ts_obj, e);
306 ts_error_writable_and_unblock_write(js, ts_obj, e);
307}
308
309void ts_ctrl_terminate(ant_t *js, ant_value_t ctrl_obj) {
310 ant_value_t ts_obj = ts_ctrl_stream(ctrl_obj);
311 ant_value_t readable = ts_readable(ts_obj);
312 ant_value_t rs_ctrl = rs_stream_controller(js, readable);
313
314 rs_controller_close(js, rs_ctrl);
315 ant_value_t writable = ts_writable(ts_obj);
316 ws_stream_t *ws = ws_get_stream(writable);
317
318 if (ws && ws->state == WS_STATE_WRITABLE) {
319 ant_value_t err = js_make_error_silent(js, JS_ERR_TYPE, "TransformStream readable side terminated");
320 ts_error_writable_and_unblock_write(js, ts_obj, err);
321 }
322}
323
324static ant_value_t ts_transform_resolve(ant_t *js, ant_value_t *args, int nargs) {
325 ant_value_t p = js_get_slot(js->current_func, SLOT_DATA);
326 js_resolve_promise(js, p, js_mkundef());
327 return js_mkundef();
328}
329
330static ant_value_t ts_transform_reject(ant_t *js, ant_value_t *args, int nargs) {
331 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA);
332 ant_value_t p = js_get_slot(wrapper, SLOT_DATA);
333 ant_value_t ts_obj = js_get_slot(wrapper, SLOT_ENTRIES);
334 ant_value_t e = (nargs > 0) ? args[0] : js_mkundef();
335 ts_error(js, ts_obj, e);
336 js_reject_promise(js, p, e);
337 return js_mkundef();
338}
339
340static ant_value_t ts_ctrl_perform_transform(ant_t *js, ant_value_t ctrl_obj, ant_value_t chunk) {
341 ant_value_t transform_fn = ts_ctrl_transform_fn(ctrl_obj);
342 ant_value_t ts_obj = ts_ctrl_stream(ctrl_obj);
343 ant_value_t p = js_mkpromise(js);
344 promise_mark_handled(p);
345
346 if (is_callable(transform_fn)) {
347 ant_value_t call_args[2] = { chunk, ctrl_obj };
348 ant_value_t result = sv_vm_call(js->vm, js, transform_fn, ts_ctrl_transformer(ctrl_obj), call_args, 2, NULL, false);
349
350 if (is_err(result)) {
351 ant_value_t err = ts_take_thrown_or(js, result);
352 ts_error(js, ts_obj, err);
353 js_reject_promise(js, p, err);
354 return p;
355 }
356
357 ant_value_t res_fn = js_heavy_mkfun(js, ts_transform_resolve, p);
358 ant_value_t wrapper = js_mkobj(js);
359 js_set_slot(wrapper, SLOT_DATA, p);
360 js_set_slot(wrapper, SLOT_ENTRIES, ts_obj);
361
362 ant_value_t rej_fn = js_heavy_mkfun(js, ts_transform_reject, wrapper);
363 ts_chain_promise(js, result, res_fn, rej_fn);
364 } else {
365 ant_value_t enqueue_result = ts_ctrl_enqueue(js, ctrl_obj, chunk);
366 if (is_err(enqueue_result)) {
367 ant_value_t err = ts_take_thrown_or(js, enqueue_result);
368 js_reject_promise(js, p, err);
369 return p;
370 }
371 js_resolve_promise(js, p, js_mkundef());
372 }
373
374 return p;
375}
376
377static ant_value_t ts_cancel_base_resolve(ant_t *js, ant_value_t *args, int nargs) {
378 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA);
379 ant_value_t p = js_get_slot(wrapper, SLOT_DATA);
380 ant_value_t ts_obj = js_get_slot(wrapper, SLOT_ENTRIES);
381 ts_clear_cancel_state(ts_obj, p);
382 js_resolve_promise(js, p, js_mkundef());
383 return js_mkundef();
384}
385
386static ant_value_t ts_cancel_base_reject(ant_t *js, ant_value_t *args, int nargs) {
387 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA);
388 ant_value_t p = js_get_slot(wrapper, SLOT_DATA);
389 ant_value_t ts_obj = js_get_slot(wrapper, SLOT_ENTRIES);
390 ant_value_t err = (nargs > 0) ? args[0] : js_mkundef();
391 ts_clear_cancel_state(ts_obj, p);
392 js_reject_promise(js, p, err);
393 return js_mkundef();
394}
395
396static ant_value_t ts_run_cancel_algorithm(ant_t *js, ant_value_t ts_obj, ant_value_t cancel_fn, ant_value_t reason, bool started_by_abort) {
397 ant_value_t existing = ts_cancel_promise(ts_obj);
398 if (vtype(existing) == T_PROMISE) return existing;
399
400 ant_value_t p = js_mkpromise(js);
401 promise_mark_handled(p);
402 ts_set_cancel_state(js, ts_obj, p, started_by_abort, is_callable(cancel_fn));
403 ts_ctrl_clear_algorithms(ts_controller(ts_obj));
404
405 ant_value_t result = js_mkundef();
406 if (is_callable(cancel_fn)) {
407 ant_value_t cancel_args[1] = { reason };
408 result = sv_vm_call(js->vm, js, cancel_fn, ts_ctrl_transformer(ts_controller(ts_obj)), cancel_args, 1, NULL, false);
409 }
410
411 if (is_err(result)) {
412 ant_value_t err = ts_take_thrown_or(js, result);
413 ts_clear_cancel_state(ts_obj, p);
414 js_reject_promise(js, p, err);
415 return p;
416 }
417
418 ant_value_t wrapper = js_mkobj(js);
419 js_set_slot(wrapper, SLOT_DATA, p);
420 js_set_slot(wrapper, SLOT_ENTRIES, ts_obj);
421
422 ant_value_t res_fn = js_heavy_mkfun(js, ts_cancel_base_resolve, wrapper);
423 ant_value_t rej_fn = js_heavy_mkfun(js, ts_cancel_base_reject, wrapper);
424 ts_chain_promise(js, result, res_fn, rej_fn);
425
426 return p;
427}
428
429static ant_value_t ts_source_cancel_resolve(ant_t *js, ant_value_t *args, int nargs) {
430 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA);
431 ant_value_t p = js_get_slot(wrapper, SLOT_DATA);
432 ant_value_t ts_obj = js_get_slot(wrapper, SLOT_ENTRIES);
433 ant_value_t reason = js_get_slot(wrapper, SLOT_AUX);
434
435 ant_value_t readable = ts_readable(ts_obj);
436 rs_stream_t *rs = rs_get_stream(readable);
437 ant_value_t settle_error = ts_cancel_settle_error(ts_obj);
438 if (is_object_type(settle_error)) {
439 js_reject_promise(js, p, settle_error);
440 return js_mkundef();
441 }
442 if (rs && rs->state == RS_STATE_ERRORED) {
443 js_reject_promise(js, p, rs_stream_error(readable));
444 return js_mkundef();
445 }
446 ant_value_t writable = ts_writable(ts_obj);
447 ws_stream_t *ws = ws_get_stream(writable);
448
449 if (ws && ws->state == WS_STATE_WRITABLE)
450 ts_error_writable_and_unblock_write(js, ts_obj, reason);
451
452 js_resolve_promise(js, p, js_mkundef());
453 return js_mkundef();
454}
455
456static ant_value_t ts_source_cancel_reject(ant_t *js, ant_value_t *args, int nargs) {
457 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA);
458 ant_value_t p = js_get_slot(wrapper, SLOT_DATA);
459 ant_value_t ts_obj = js_get_slot(wrapper, SLOT_ENTRIES);
460 ant_value_t err = (nargs > 0) ? args[0] : js_mkundef();
461 ts_error_writable_and_unblock_write(js, ts_obj, err);
462 js_reject_promise(js, p, err);
463 return js_mkundef();
464}
465
466static ant_value_t ts_abort_cancel_resolve(ant_t *js, ant_value_t *args, int nargs) {
467 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA);
468 ant_value_t p = js_get_slot(wrapper, SLOT_DATA);
469 ant_value_t ts_obj = js_get_slot(wrapper, SLOT_ENTRIES);
470 ant_value_t reason = js_get_slot(wrapper, SLOT_AUX);
471
472 ant_value_t readable = ts_readable(ts_obj);
473 rs_stream_t *rs = rs_get_stream(readable);
474
475 if (rs && rs->state == RS_STATE_ERRORED) {
476 js_reject_promise(js, p, rs_stream_error(readable));
477 return js_mkundef();
478 }
479
480 if (ts_cancel_joined_abort(ts_obj)) js_set_slot_wb(js, ts_obj, SLOT_RS_SIZE, reason);
481 ts_error(js, ts_obj, reason);
482
483 if (ts_cancel_joined_abort(ts_obj)) js_reject_promise(js, p, reason);
484 else js_resolve_promise(js, p, js_mkundef());
485
486 return js_mkundef();
487}
488
489static ant_value_t ts_abort_cancel_reject(ant_t *js, ant_value_t *args, int nargs) {
490 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA);
491 ant_value_t p = js_get_slot(wrapper, SLOT_DATA);
492 ant_value_t ts_obj = js_get_slot(wrapper, SLOT_ENTRIES);
493 ant_value_t err = (nargs > 0) ? args[0] : js_mkundef();
494 ts_error(js, ts_obj, err);
495 js_reject_promise(js, p, err);
496 return js_mkundef();
497}
498
499static ant_value_t ts_close_cancel_resolve(ant_t *js, ant_value_t *args, int nargs) {
500 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA);
501 ant_value_t p = js_get_slot(wrapper, SLOT_DATA);
502 ant_value_t ts_obj = js_get_slot(wrapper, SLOT_ENTRIES);
503 ant_value_t readable = ts_readable(ts_obj);
504 rs_stream_t *rs = rs_get_stream(readable);
505 ant_value_t settle_error = ts_cancel_settle_error(ts_obj);
506 if (is_object_type(settle_error)) {
507 js_reject_promise(js, p, settle_error);
508 return js_mkundef();
509 }
510 if (rs && rs->state == RS_STATE_ERRORED) {
511 js_reject_promise(js, p, rs_stream_error(readable));
512 return js_mkundef();
513 }
514 js_resolve_promise(js, p, js_mkundef());
515 return js_mkundef();
516}
517
518static ant_value_t ts_close_cancel_reject(ant_t *js, ant_value_t *args, int nargs) {
519 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA);
520 ant_value_t p = js_get_slot(wrapper, SLOT_DATA);
521 ant_value_t err = (nargs > 0) ? args[0] : js_mkundef();
522 js_reject_promise(js, p, err);
523 return js_mkundef();
524}
525
526static ant_value_t ts_sink_write_bp_resolve(ant_t *js, ant_value_t *args, int nargs) {
527 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA);
528 ant_value_t ctrl_obj = js_get_slot(wrapper, SLOT_DATA);
529 ant_value_t chunk = js_get_slot(wrapper, SLOT_ENTRIES);
530 ant_value_t ts_obj = js_get_slot(wrapper, SLOT_CTOR);
531 ws_stream_t *ws = ws_get_stream(ts_writable(ts_obj));
532
533 if (ws && ws->state == WS_STATE_ERRORING) {
534 ant_value_t err = ts_writable_stored_error(ts_obj);
535 if (!is_object_type(err))
536 err = js_make_error_silent(js, JS_ERR_TYPE, "WritableStream is in erroring state");
537 ant_value_t fp = ts_ctrl_finish_promise(ctrl_obj);
538 if (vtype(fp) == T_PROMISE) js_reject_promise(js, fp, err);
539 return js_mkundef();
540 }
541
542 ant_value_t transform_p = ts_ctrl_perform_transform(js, ctrl_obj, chunk);
543 ant_value_t fp = ts_ctrl_finish_promise(ctrl_obj);
544 if (vtype(fp) == T_PROMISE) {
545 ant_value_t resolve_fn = js_heavy_mkfun(js, ts_transform_resolve, fp);
546 ant_value_t rej_wrapper = js_mkobj(js);
547 js_set_slot(rej_wrapper, SLOT_DATA, fp);
548 js_set_slot(rej_wrapper, SLOT_ENTRIES, ts_obj);
549 ant_value_t reject_fn = js_heavy_mkfun(js, ts_transform_reject, rej_wrapper);
550 ts_chain_promise(js, transform_p, resolve_fn, reject_fn);
551 }
552 return js_mkundef();
553}
554
555static ant_value_t ts_sink_write(ant_t *js, ant_value_t *args, int nargs) {
556 ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA);
557 ant_value_t chunk = (nargs > 0) ? args[0] : js_mkundef();
558 ant_value_t ctrl_obj = ts_controller(ts_obj);
559
560 ant_value_t finish_p = js_mkpromise(js);
561 promise_mark_handled(finish_p);
562 js_set_slot_wb(js, ctrl_obj, SLOT_RS_PULL, finish_p);
563
564 if (ts_get_backpressure(ts_obj)) {
565 ant_value_t wrapper = js_mkobj(js);
566 js_set_slot(wrapper, SLOT_DATA, ctrl_obj);
567 js_set_slot(wrapper, SLOT_ENTRIES, chunk);
568 js_set_slot(wrapper, SLOT_CTOR, ts_obj);
569 ant_value_t res_fn = js_heavy_mkfun(js, ts_sink_write_bp_resolve, wrapper);
570 ant_value_t rej_wrapper = js_mkobj(js);
571 js_set_slot(rej_wrapper, SLOT_DATA, finish_p);
572 js_set_slot(rej_wrapper, SLOT_ENTRIES, ts_obj);
573 ant_value_t rej_fn = js_heavy_mkfun(js, ts_transform_reject, rej_wrapper);
574 ant_value_t bp = ts_bp_promise(ts_obj);
575 ts_chain_promise(js, bp, res_fn, rej_fn);
576 } else {
577 ant_value_t transform_p = ts_ctrl_perform_transform(js, ctrl_obj, chunk);
578 ant_value_t resolve_fn = js_heavy_mkfun(js, ts_transform_resolve, finish_p);
579 ant_value_t rej_wrapper = js_mkobj(js);
580 js_set_slot(rej_wrapper, SLOT_DATA, finish_p);
581 js_set_slot(rej_wrapper, SLOT_ENTRIES, ts_obj);
582 ant_value_t reject_fn = js_heavy_mkfun(js, ts_transform_reject, rej_wrapper);
583 ts_chain_promise(js, transform_p, resolve_fn, reject_fn);
584 }
585
586 return finish_p;
587}
588
589static ant_value_t ts_sink_abort(ant_t *js, ant_value_t *args, int nargs) {
590 ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA);
591 ant_value_t ctrl_obj = ts_controller(ts_obj);
592 ant_value_t cancel_fn = ts_ctrl_cancel_fn(ctrl_obj);
593 ant_value_t reason = (nargs > 0) ? args[0] : js_mkundef();
594
595 bool joined_source_cancel = vtype(ts_cancel_promise(ts_obj)) == T_PROMISE && !ts_cancel_started_by_abort(ts_obj);
596 if (joined_source_cancel && ts_cancel_has_user_handler(ts_obj))
597 js_set_slot(ts_obj, SLOT_WS_WRITE, js_true);
598
599 ant_value_t p = js_mkpromise(js);
600 ant_value_t base = ts_run_cancel_algorithm(js, ts_obj, cancel_fn, reason, true);
601 ant_value_t wrapper = js_mkobj(js);
602 js_set_slot(wrapper, SLOT_DATA, p);
603 js_set_slot(wrapper, SLOT_ENTRIES, ts_obj);
604 js_set_slot(wrapper, SLOT_AUX, reason);
605 js_set_slot(wrapper, SLOT_CTOR, ts_cancel_started_by_abort(ts_obj) ? js_true : js_false);
606
607 ant_value_t res_fn = js_heavy_mkfun(js, ts_abort_cancel_resolve, wrapper);
608 ant_value_t rej_fn = js_heavy_mkfun(js, ts_abort_cancel_reject, wrapper);
609 ts_chain_promise(js, base, res_fn, rej_fn);
610
611 return p;
612}
613
614static ant_value_t ts_sink_close_resolve(ant_t *js, ant_value_t *args, int nargs) {
615 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA);
616 ant_value_t p = js_get_slot(wrapper, SLOT_DATA);
617 ant_value_t ts_obj = js_get_slot(wrapper, SLOT_ENTRIES);
618
619 ant_value_t readable = ts_readable(ts_obj);
620 rs_stream_t *rs = rs_get_stream(readable);
621 ant_value_t rs_ctrl = rs_stream_controller(js, readable);
622 ts_set_flushing(ts_obj, false);
623
624 if (rs && rs->state == RS_STATE_READABLE) {
625 rs_controller_close(js, rs_ctrl);
626 js_resolve_promise(js, p, js_mkundef());
627 } else if (rs && rs->state == RS_STATE_CLOSED) {
628 js_resolve_promise(js, p, js_mkundef());
629 } else if (rs && rs->state == RS_STATE_ERRORED) {
630 js_reject_promise(js, p, rs_stream_error(readable));
631 } else {
632 js_reject_promise(js, p, js_make_error_silent(js, JS_ERR_TYPE, "TransformStream readable side is not in a readable state"));
633 }
634
635 return js_mkundef();
636}
637
638static ant_value_t ts_sink_close_reject(ant_t *js, ant_value_t *args, int nargs) {
639 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA);
640 ant_value_t p = js_get_slot(wrapper, SLOT_DATA);
641 ant_value_t ts_obj = js_get_slot(wrapper, SLOT_ENTRIES);
642 ant_value_t e = (nargs > 0) ? args[0] : js_mkundef();
643 ts_set_flushing(ts_obj, false);
644 ts_error(js, ts_obj, e);
645 js_reject_promise(js, p, e);
646 return js_mkundef();
647}
648
649static ant_value_t ts_sink_close(ant_t *js, ant_value_t *args, int nargs) {
650 ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA);
651 ant_value_t ctrl_obj = ts_controller(ts_obj);
652 ant_value_t readable = ts_readable(ts_obj);
653
654 ant_value_t flush_fn = ts_ctrl_flush_fn(ctrl_obj);
655 ant_value_t p = js_mkpromise(js);
656 promise_mark_handled(p);
657
658 ant_value_t cancel_p = ts_cancel_promise(ts_obj);
659 if (vtype(cancel_p) == T_PROMISE) {
660 ant_value_t wrapper = js_mkobj(js);
661 js_set_slot(wrapper, SLOT_DATA, p);
662 js_set_slot(wrapper, SLOT_ENTRIES, ts_obj);
663 ant_value_t res_fn = js_heavy_mkfun(js, ts_close_cancel_resolve, wrapper);
664 ant_value_t rej_fn = js_heavy_mkfun(js, ts_close_cancel_reject, wrapper);
665 ts_chain_promise(js, cancel_p, res_fn, rej_fn);
666 return p;
667 }
668
669 ts_ctrl_clear_algorithms(ctrl_obj);
670 ts_set_flushing(ts_obj, true);
671
672 if (is_callable(flush_fn)) {
673 ant_value_t flush_args[1] = { ctrl_obj };
674 ant_value_t result = sv_vm_call(js->vm, js, flush_fn, ts_ctrl_transformer(ctrl_obj), flush_args, 1, NULL, false);
675
676 if (is_err(result)) {
677 ant_value_t err = ts_take_thrown_or(js, result);
678 ts_error(js, ts_obj, err);
679 ts_set_flushing(ts_obj, false);
680 js_reject_promise(js, p, err);
681 return p;
682 }
683
684 ant_value_t wrapper = js_mkobj(js);
685 js_set_slot(wrapper, SLOT_DATA, p);
686 js_set_slot(wrapper, SLOT_ENTRIES, ts_obj);
687 ant_value_t res_fn = js_heavy_mkfun(js, ts_sink_close_resolve, wrapper);
688 ant_value_t rej_fn = js_heavy_mkfun(js, ts_sink_close_reject, wrapper);
689
690 ts_chain_promise(js, result, res_fn, rej_fn);
691 } else {
692 rs_stream_t *rs = rs_get_stream(readable);
693 if (rs && rs->state == RS_STATE_READABLE) {
694 ant_value_t rs_ctrl = rs_stream_controller(js, readable);
695 rs_controller_t *rc = rs_get_controller(rs_ctrl);
696 if (rc) rc->defer_close = true;
697 rs_controller_close(js, rs_ctrl);
698 if (rc) rc->defer_close = false;
699 }
700 ts_set_flushing(ts_obj, false);
701 js_resolve_promise(js, p, js_mkundef());
702 }
703
704 return p;
705}
706
707static ant_value_t ts_source_pull_resolve(ant_t *js, ant_value_t *args, int nargs) {
708 ant_value_t p = js_get_slot(js->current_func, SLOT_DATA);
709 js_resolve_promise(js, p, js_mkundef());
710 return js_mkundef();
711}
712
713static ant_value_t ts_source_pull(ant_t *js, ant_value_t *args, int nargs) {
714 ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA);
715
716 if (ts_get_backpressure(ts_obj)) {
717 ts_set_backpressure(js, ts_obj, false);
718 ant_value_t p = js_mkpromise(js);
719 js_resolve_promise(js, p, js_mkundef());
720 return p;
721 }
722
723 ant_value_t p = js_mkpromise(js);
724 js_resolve_promise(js, p, js_mkundef());
725 return p;
726}
727
728static ant_value_t ts_source_cancel(ant_t *js, ant_value_t *args, int nargs) {
729 ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA);
730 ant_value_t ctrl_obj = ts_controller(ts_obj);
731 ant_value_t cancel_fn = ts_ctrl_cancel_fn(ctrl_obj);
732 ant_value_t reason = (nargs > 0) ? args[0] : js_mkundef();
733
734 if (ts_is_flushing(ts_obj)) {
735 ant_value_t p = js_mkpromise(js);
736 js_resolve_promise(js, p, js_mkundef());
737 return p;
738 }
739
740 ant_value_t p = js_mkpromise(js);
741 ant_value_t base = ts_run_cancel_algorithm(js, ts_obj, cancel_fn, reason, false);
742 ant_value_t wrapper = js_mkobj(js);
743 js_set_slot(wrapper, SLOT_DATA, p);
744 js_set_slot(wrapper, SLOT_ENTRIES, ts_obj);
745 js_set_slot(wrapper, SLOT_AUX, reason);
746 js_set_slot(wrapper, SLOT_CTOR, ts_cancel_started_by_abort(ts_obj) ? js_true : js_false);
747 ant_value_t res_fn = js_heavy_mkfun(js, ts_source_cancel_resolve, wrapper);
748 ant_value_t rej_fn = js_heavy_mkfun(js, ts_source_cancel_reject, wrapper);
749 ts_chain_promise(js, base, res_fn, rej_fn);
750 return p;
751}
752
753static ant_value_t js_ts_ctrl_get_desired_size(ant_t *js, ant_value_t *args, int nargs) {
754 ant_value_t ts_obj = ts_ctrl_stream(js->this_val);
755 ant_value_t readable = ts_readable(ts_obj);
756 ant_value_t rs_ctrl = rs_stream_controller(js, readable);
757 rs_controller_t *rc = rs_get_controller(rs_ctrl);
758 rs_stream_t *rs = rs_get_stream(readable);
759 if (!rc || !rs) return js_mknull();
760 if (rs->state == RS_STATE_ERRORED) return js_mknull();
761 if (rs->state == RS_STATE_CLOSED) return js_mknum(0);
762 return js_mknum(rc->strategy_hwm - rc->queue_total_size);
763}
764
765static ant_value_t js_ts_ctrl_enqueue(ant_t *js, ant_value_t *args, int nargs) {
766 ant_value_t ts_obj = ts_ctrl_stream(js->this_val);
767 ant_value_t readable = ts_readable(ts_obj);
768 rs_stream_t *rs = rs_get_stream(readable);
769 if (!rs || rs->state != RS_STATE_READABLE)
770 return js_mkerr_typed(js, JS_ERR_TYPE, "Readable side is not in a readable state");
771
772 ant_value_t chunk = (nargs > 0) ? args[0] : js_mkundef();
773 return ts_ctrl_enqueue(js, js->this_val, chunk);
774}
775
776static ant_value_t js_ts_ctrl_error(ant_t *js, ant_value_t *args, int nargs) {
777 ant_value_t e = (nargs > 0) ? args[0] : js_mkundef();
778 ts_ctrl_error(js, js->this_val, e);
779 return js_mkundef();
780}
781
782static ant_value_t js_ts_ctrl_terminate(ant_t *js, ant_value_t *args, int nargs) {
783 ts_ctrl_terminate(js, js->this_val);
784 return js_mkundef();
785}
786
787static ant_value_t js_ts_get_readable(ant_t *js, ant_value_t *args, int nargs) {
788 if (!ts_is_stream(js->this_val)) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid TransformStream");
789 return ts_readable(js->this_val);
790}
791
792static ant_value_t js_ts_get_writable(ant_t *js, ant_value_t *args, int nargs) {
793 if (!ts_is_stream(js->this_val)) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid TransformStream");
794 return ts_writable(js->this_val);
795}
796
797static ant_value_t ts_start_resolve(ant_t *js, ant_value_t *args, int nargs) {
798 ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA);
799 ant_value_t writable = ts_writable(ts_obj);
800 ant_value_t ws_ctrl = ws_stream_controller(writable);
801 ws_controller_t *wc = ws_get_controller(ws_ctrl);
802 if (wc) wc->started = true;
803 ws_default_controller_advance_queue_if_needed(js, ws_ctrl);
804
805 ant_value_t readable = ts_readable(ts_obj);
806 ant_value_t rs_ctrl = rs_stream_controller(js, readable);
807 rs_controller_t *rc = rs_get_controller(rs_ctrl);
808 if (rc) {
809 rc->started = true;
810 rc->pulling = false;
811 rc->pull_again = false;
812 rs_default_controller_call_pull_if_needed(js, rs_ctrl);
813 }
814
815 return js_mkundef();
816}
817
818static ant_value_t ts_start_reject(ant_t *js, ant_value_t *args, int nargs) {
819 ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA);
820 ant_value_t e = (nargs > 0) ? args[0] : js_mkundef();
821
822 ant_value_t writable = ts_writable(ts_obj);
823 ant_value_t ws_ctrl = ws_stream_controller(writable);
824 ws_controller_t *wc = ws_get_controller(ws_ctrl);
825 if (wc) wc->started = true;
826
827 ant_value_t readable = ts_readable(ts_obj);
828 ant_value_t rs_ctrl = rs_stream_controller(js, readable);
829 rs_controller_t *rc = rs_get_controller(rs_ctrl);
830 if (rc) rc->started = true;
831
832 readable_stream_error(js, readable, e);
833
834 ws_stream_t *ws = ws_get_stream(writable);
835 if (ws && ws->state == WS_STATE_WRITABLE)
836 ws_default_controller_error(js, ws_ctrl, e);
837 else if (ws && ws->state == WS_STATE_ERRORING)
838 writable_stream_finish_erroring(js, writable);
839
840 return js_mkundef();
841}
842
843ant_value_t js_ts_ctor(ant_t *js, ant_value_t *args, int nargs) {
844 if (vtype(js->new_target) == T_UNDEF)
845 return js_mkerr_typed(js, JS_ERR_TYPE, "TransformStream constructor requires 'new'");
846
847 ant_value_t transformer = js_mkundef();
848 if (nargs > 0 && !is_undefined(args[0]))
849 transformer = args[0];
850
851 if (is_object_type(transformer)) {
852 ant_value_t rt_val = js_getprop_fallback(js, transformer, "readableType");
853 if (!is_undefined(rt_val))
854 return js_mkerr_typed(js, JS_ERR_RANGE, "readableType is not supported");
855 ant_value_t wt_val = js_getprop_fallback(js, transformer, "writableType");
856 if (!is_undefined(wt_val))
857 return js_mkerr_typed(js, JS_ERR_RANGE, "writableType is not supported");
858 }
859
860 ant_value_t writable_strategy = js_mkundef();
861 if (nargs > 1 && !is_undefined(args[1]) && !is_null(args[1]))
862 writable_strategy = args[1];
863
864 ant_value_t readable_strategy = js_mkundef();
865 if (nargs > 2 && !is_undefined(args[2]) && !is_null(args[2]))
866 readable_strategy = args[2];
867
868 double writable_hwm = 1;
869 ant_value_t writable_size_fn = js_mkundef();
870 if (is_object_type(writable_strategy)) {
871 ant_value_t hwm_val = js_getprop_fallback(js, writable_strategy, "highWaterMark");
872 if (is_err(hwm_val)) return hwm_val;
873 if (!is_undefined(hwm_val)) {
874 writable_hwm = js_to_number(js, hwm_val);
875 if (writable_hwm != writable_hwm || writable_hwm < 0)
876 return js_mkerr_typed(js, JS_ERR_RANGE, "Invalid highWaterMark");
877 }
878 ant_value_t s = js_getprop_fallback(js, writable_strategy, "size");
879 if (is_err(s)) return s;
880 if (!is_undefined(s)) {
881 if (!is_callable(s)) return js_mkerr_typed(js, JS_ERR_TYPE, "size must be a function");
882 writable_size_fn = s;
883 }
884 }
885
886 double readable_hwm = 0;
887 ant_value_t readable_size_fn = js_mkundef();
888 if (is_object_type(readable_strategy)) {
889 ant_value_t hwm_val = js_getprop_fallback(js, readable_strategy, "highWaterMark");
890 if (is_err(hwm_val)) return hwm_val;
891 if (!is_undefined(hwm_val)) {
892 readable_hwm = js_to_number(js, hwm_val);
893 if (readable_hwm != readable_hwm || readable_hwm < 0)
894 return js_mkerr_typed(js, JS_ERR_RANGE, "Invalid highWaterMark");
895 }
896 ant_value_t s = js_getprop_fallback(js, readable_strategy, "size");
897 if (is_err(s)) return s;
898 if (!is_undefined(s)) {
899 if (!is_callable(s)) return js_mkerr_typed(js, JS_ERR_TYPE, "size must be a function");
900 readable_size_fn = s;
901 }
902 }
903
904 ant_value_t transform_fn = js_mkundef();
905 ant_value_t flush_fn = js_mkundef();
906 ant_value_t cancel_fn = js_mkundef();
907 ant_value_t start_fn = js_mkundef();
908
909 if (is_object_type(transformer)) {
910 ant_value_t tv = js_getprop_fallback(js, transformer, "transform");
911 if (is_err(tv)) return tv;
912 if (!is_undefined(tv)) {
913 if (!is_callable(tv)) return js_mkerr_typed(js, JS_ERR_TYPE, "transform must be a function");
914 transform_fn = tv;
915 }
916 ant_value_t fv = js_getprop_fallback(js, transformer, "flush");
917 if (is_err(fv)) return fv;
918 if (!is_undefined(fv)) {
919 if (!is_callable(fv)) return js_mkerr_typed(js, JS_ERR_TYPE, "flush must be a function");
920 flush_fn = fv;
921 }
922 ant_value_t cv = js_getprop_fallback(js, transformer, "cancel");
923 if (is_err(cv)) return cv;
924 if (!is_undefined(cv)) {
925 if (!is_callable(cv)) return js_mkerr_typed(js, JS_ERR_TYPE, "cancel must be a function");
926 cancel_fn = cv;
927 }
928 ant_value_t sv = js_getprop_fallback(js, transformer, "start");
929 if (is_err(sv)) return sv;
930 if (!is_undefined(sv)) {
931 if (!is_callable(sv)) return js_mkerr_typed(js, JS_ERR_TYPE, "start must be a function");
932 start_fn = sv;
933 }
934 }
935
936 ant_value_t ts_obj = js_mkobj(js);
937 ant_value_t proto = js_instance_proto_from_new_target(js, g_ts_proto);
938 if (is_object_type(proto)) js_set_proto_init(ts_obj, proto);
939 js_set_slot(ts_obj, SLOT_BRAND, js_mknum(BRAND_TRANSFORM_STREAM));
940 js_set_slot(ts_obj, SLOT_DATA, js_mknum(0));
941
942 ant_value_t ctrl_obj = js_mkobj(js);
943 js_set_proto_init(ctrl_obj, g_ts_ctrl_proto);
944 js_set_slot(ctrl_obj, SLOT_BRAND, js_mknum(BRAND_TRANSFORM_STREAM_CONTROLLER));
945 js_set_slot(ctrl_obj, SLOT_DATA, ts_obj);
946 js_set_slot(ctrl_obj, SLOT_ENTRIES, transform_fn);
947 js_set_slot(ctrl_obj, SLOT_CTOR, flush_fn);
948 js_set_slot(ctrl_obj, SLOT_AUX, cancel_fn);
949 js_set_slot(ctrl_obj, SLOT_SETTLED, transformer);
950 js_set_slot(ctrl_obj, SLOT_RS_PULL, js_mkundef());
951 js_set_slot(ts_obj, SLOT_DEFAULT, ctrl_obj);
952 js_set_slot(ts_obj, SLOT_RS_CANCEL, js_mkundef());
953 js_set_slot(ts_obj, SLOT_WS_ABORT, js_false);
954 js_set_slot(ts_obj, SLOT_WS_CLOSE, js_false);
955 js_set_slot(ts_obj, SLOT_RS_SIZE, js_mkundef());
956 js_set_slot(ts_obj, SLOT_WS_WRITE, js_false);
957 js_set_slot(ts_obj, SLOT_WS_SIGNAL, js_false);
958
959 ant_value_t sink_write = js_heavy_mkfun(js, ts_sink_write, ts_obj);
960 ant_value_t sink_abort = js_heavy_mkfun(js, ts_sink_abort, ts_obj);
961 ant_value_t sink_close = js_heavy_mkfun(js, ts_sink_close, ts_obj);
962
963 ant_value_t source_pull = js_heavy_mkfun(js, ts_source_pull, ts_obj);
964 ant_value_t source_cancel = js_heavy_mkfun(js, ts_source_cancel, ts_obj);
965
966 rs_stream_t *rst = calloc(1, sizeof(rs_stream_t));
967 if (!rst) return js_mkerr(js, "out of memory");
968 rst->state = RS_STATE_READABLE;
969
970 ant_value_t rs_obj = js_mkobj(js);
971 js_set_proto_init(rs_obj, g_rs_proto);
972 js_set_slot(rs_obj, SLOT_BRAND, js_mknum(BRAND_READABLE_STREAM));
973 js_set_slot(rs_obj, SLOT_DATA, ANT_PTR(rst));
974 js_set_finalizer(rs_obj, ts_rs_finalize);
975
976 rs_controller_t *rcc = calloc(1, sizeof(rs_controller_t));
977 if (!rcc) { free(rst); return js_mkerr(js, "out of memory"); }
978 rcc->strategy_hwm = readable_hwm;
979
980 ant_value_t rs_ctrl_obj = js_mkobj(js);
981 js_set_proto_init(rs_ctrl_obj, g_controller_proto);
982 js_set_slot(rs_ctrl_obj, SLOT_BRAND, js_mknum(BRAND_READABLE_STREAM_CONTROLLER));
983 js_set_slot(rs_ctrl_obj, SLOT_DATA, ANT_PTR(rcc));
984 js_set_slot(rs_ctrl_obj, SLOT_ENTRIES, rs_obj);
985 js_set_slot(rs_ctrl_obj, SLOT_RS_PULL, source_pull);
986 js_set_slot(rs_ctrl_obj, SLOT_RS_CANCEL, source_cancel);
987 js_set_slot(rs_ctrl_obj, SLOT_RS_SIZE, readable_size_fn);
988 js_set_slot(rs_ctrl_obj, SLOT_AUX, js_mkarr(js));
989 js_set_finalizer(rs_ctrl_obj, ts_rs_ctrl_finalize);
990 js_set_slot(rs_obj, SLOT_ENTRIES, rs_ctrl_obj);
991
992 js_set_slot(ts_obj, SLOT_ENTRIES, rs_obj);
993
994 ws_stream_t *wst = calloc(1, sizeof(ws_stream_t));
995 if (!wst) return js_mkerr(js, "out of memory");
996 wst->state = WS_STATE_WRITABLE;
997
998 ant_value_t ws_obj = js_mkobj(js);
999 js_set_proto_init(ws_obj, g_ws_proto);
1000 js_set_slot(ws_obj, SLOT_BRAND, js_mknum(BRAND_WRITABLE_STREAM));
1001 js_set_slot(ws_obj, SLOT_DATA, ANT_PTR(wst));
1002 js_set_slot(ws_obj, SLOT_SETTLED, js_mkarr(js));
1003 js_set_finalizer(ws_obj, ts_ws_finalize);
1004
1005 js_set_slot(ts_obj, SLOT_CTOR, ws_obj);
1006
1007 ant_value_t bp_promise = js_mkpromise(js);
1008 js_set_slot_wb(js, ts_obj, SLOT_AUX, bp_promise);
1009
1010 ts_set_backpressure(js, ts_obj, true);
1011
1012 ws_controller_t *wc = calloc(1, sizeof(ws_controller_t));
1013 if (!wc) { free(wst); return js_mkerr(js, "out of memory"); }
1014 wc->strategy_hwm = writable_hwm;
1015
1016 ant_value_t ws_ctrl_obj = js_mkobj(js);
1017 js_set_proto_init(ws_ctrl_obj, g_ws_controller_proto);
1018 js_set_slot(ws_ctrl_obj, SLOT_BRAND, js_mknum(BRAND_WRITABLE_STREAM_CONTROLLER));
1019 js_set_slot(ws_ctrl_obj, SLOT_DATA, ANT_PTR(wc));
1020 js_set_slot(ws_ctrl_obj, SLOT_ENTRIES, ws_obj);
1021 js_set_slot(ws_ctrl_obj, SLOT_WS_WRITE, sink_write);
1022 js_set_slot(ws_ctrl_obj, SLOT_WS_CLOSE, sink_close);
1023 js_set_slot(ws_ctrl_obj, SLOT_WS_ABORT, sink_abort);
1024 js_set_slot(ws_ctrl_obj, SLOT_RS_SIZE, writable_size_fn);
1025 js_set_slot(ws_ctrl_obj, SLOT_CTOR, js_mkundef());
1026 js_set_slot(ws_ctrl_obj, SLOT_AUX, js_mkarr(js));
1027 js_set_finalizer(ws_ctrl_obj, ts_ws_ctrl_finalize);
1028
1029 js_set_slot(ws_obj, SLOT_ENTRIES, ws_ctrl_obj);
1030
1031 if (is_callable(start_fn)) {
1032 ant_value_t start_args[1] = { ctrl_obj };
1033 ant_value_t start_result = sv_vm_call(js->vm, js, start_fn, transformer, start_args, 1, NULL, false);
1034 if (is_err(start_result)) { return start_result; }
1035
1036 if (vtype(start_result) == T_PROMISE) {
1037 ant_value_t resolve_fn = js_heavy_mkfun(js, ts_start_resolve, ts_obj);
1038 ant_value_t reject_fn = js_heavy_mkfun(js, ts_start_reject, ts_obj);
1039 js_promise_then(js, start_result, resolve_fn, reject_fn);
1040 }
1041
1042 if (vtype(start_result) != T_PROMISE) {
1043 ant_value_t resolved = js_mkpromise(js);
1044 js_resolve_promise(js, resolved, js_mkundef());
1045 ant_value_t res_fn = js_heavy_mkfun(js, ts_start_resolve, ts_obj);
1046 ant_value_t rej_fn = js_heavy_mkfun(js, ts_start_reject, ts_obj);
1047 js_promise_then(js, resolved, res_fn, rej_fn);
1048 }
1049 } else {
1050 ant_value_t resolved = js_mkpromise(js);
1051 js_resolve_promise(js, resolved, js_mkundef());
1052 ant_value_t res_fn = js_heavy_mkfun(js, ts_start_resolve, ts_obj);
1053 ant_value_t rej_fn = js_heavy_mkfun(js, ts_start_reject, ts_obj);
1054 js_promise_then(js, resolved, res_fn, rej_fn);
1055 }
1056
1057 return ts_obj;
1058}
1059
1060static ant_value_t js_ts_ctrl_ctor(ant_t *js, ant_value_t *args, int nargs) {
1061 return js_mkerr_typed(js, JS_ERR_TYPE, "TransformStreamDefaultController cannot be constructed directly");
1062}
1063
1064void init_transform_stream_module(void) {
1065 ant_t *js = rt->js;
1066 ant_value_t g = js_glob(js);
1067
1068 g_ts_ctrl_proto = js_mkobj(js);
1069 js_set_getter_desc(js, g_ts_ctrl_proto, "desiredSize", 11, js_mkfun(js_ts_ctrl_get_desired_size), JS_DESC_C);
1070 js_set(js, g_ts_ctrl_proto, "enqueue", js_mkfun(js_ts_ctrl_enqueue));
1071 js_set_descriptor(js, g_ts_ctrl_proto, "enqueue", 7, JS_DESC_W | JS_DESC_C);
1072 js_set(js, g_ts_ctrl_proto, "error", js_mkfun(js_ts_ctrl_error));
1073 js_set_descriptor(js, g_ts_ctrl_proto, "error", 5, JS_DESC_W | JS_DESC_C);
1074 js_set(js, g_ts_ctrl_proto, "terminate", js_mkfun(js_ts_ctrl_terminate));
1075 js_set_descriptor(js, g_ts_ctrl_proto, "terminate", 9, JS_DESC_W | JS_DESC_C);
1076 js_set_sym(js, g_ts_ctrl_proto, get_toStringTag_sym(), js_mkstr(js, "TransformStreamDefaultController", 32));
1077
1078 ant_value_t ctrl_ctor = js_make_ctor(js, js_ts_ctrl_ctor, g_ts_ctrl_proto, "TransformStreamDefaultController", 32);
1079 js_set(js, g, "TransformStreamDefaultController", ctrl_ctor);
1080 js_set_descriptor(js, g, "TransformStreamDefaultController", 32, JS_DESC_W | JS_DESC_C);
1081
1082 g_ts_proto = js_mkobj(js);
1083 js_set_getter_desc(js, g_ts_proto, "readable", 8, js_mkfun(js_ts_get_readable), JS_DESC_C);
1084 js_set_getter_desc(js, g_ts_proto, "writable", 8, js_mkfun(js_ts_get_writable), JS_DESC_C);
1085 js_set_sym(js, g_ts_proto, get_toStringTag_sym(), js_mkstr(js, "TransformStream", 15));
1086
1087 ant_value_t ts_ctor = js_make_ctor(js, js_ts_ctor, g_ts_proto, "TransformStream", 15);
1088 js_set(js, g, "TransformStream", ts_ctor);
1089 js_set_descriptor(js, g, "TransformStream", 15, JS_DESC_W | JS_DESC_C);
1090}
1091
1092void gc_mark_transform_streams(ant_t *js, void (*mark)(ant_t *, ant_value_t)) {
1093 mark(js, g_ts_proto);
1094 mark(js, g_ts_ctrl_proto);
1095}