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