script/dom/transformstreamdefaultcontroller.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::RefCell;
6use std::rc::Rc;
7
8use dom_struct::dom_struct;
9use js::jsapi::{
10 ExceptionStackBehavior, Heap, JS_IsExceptionPending, JS_SetPendingException, JSObject,
11};
12use js::jsval::UndefinedValue;
13use js::rust::{HandleObject as SafeHandleObject, HandleValue as SafeHandleValue};
14
15use super::bindings::cell::DomRefCell;
16use super::bindings::codegen::Bindings::TransformerBinding::{
17 TransformerCancelCallback, TransformerFlushCallback, TransformerTransformCallback,
18};
19use super::types::TransformStream;
20use crate::dom::bindings::callback::ExceptionHandling;
21use crate::dom::bindings::codegen::Bindings::TransformStreamDefaultControllerBinding::TransformStreamDefaultControllerMethods;
22use crate::dom::bindings::codegen::Bindings::TransformerBinding::Transformer;
23use crate::dom::bindings::error::{Error, ErrorToJsval, Fallible};
24use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
25use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
26use crate::dom::globalscope::GlobalScope;
27use crate::dom::promise::Promise;
28use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler};
29use crate::dom::textdecodercommon::TextDecoderCommon;
30use crate::dom::textdecoderstream::{decode_and_enqueue_a_chunk, flush_and_enqueue};
31use crate::dom::textencoderstream::{Encoder, encode_and_enqueue_a_chunk, encode_and_flush};
32use crate::realms::{InRealm, enter_realm};
33use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
34
35impl js::gc::Rootable for TransformTransformPromiseRejection {}
36
37/// Reacting to transformPromise as part of
38/// <https://streams.spec.whatwg.org/#transform-stream-default-controller-perform-transform>
39#[derive(JSTraceable, MallocSizeOf)]
40#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
41struct TransformTransformPromiseRejection {
42 controller: Dom<TransformStreamDefaultController>,
43}
44
45impl Callback for TransformTransformPromiseRejection {
46 /// Reacting to transformPromise with the following fulfillment steps:
47 #[allow(unsafe_code)]
48 fn callback(&self, cx: SafeJSContext, v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) {
49 // Perform ! TransformStreamError(controller.[[stream]], r).
50 self.controller
51 .error(cx, &self.controller.global(), v, can_gc);
52
53 // Throw r.
54 // Note: this is done part of perform_transform().
55 }
56}
57
58/// The type of transformer algorithms we are using
59#[derive(JSTraceable)]
60pub(crate) enum TransformerType {
61 /// Algorithms provided by Js callbacks
62 Js {
63 /// <https://streams.spec.whatwg.org/#transformstreamdefaultcontroller-cancelalgorithm>
64 cancel: RefCell<Option<Rc<TransformerCancelCallback>>>,
65
66 /// <https://streams.spec.whatwg.org/#transformstreamdefaultcontroller-flushalgorithm>
67 flush: RefCell<Option<Rc<TransformerFlushCallback>>>,
68
69 /// <https://streams.spec.whatwg.org/#transformstreamdefaultcontroller-transformalgorithm>
70 transform: RefCell<Option<Rc<TransformerTransformCallback>>>,
71
72 /// The JS object used as `this` when invoking sink algorithms.
73 transform_obj: Heap<*mut JSObject>,
74 },
75 /// Algorithms supporting `TextDecoderStream` are implemented in Rust
76 ///
77 /// <https://encoding.spec.whatwg.org/#textdecodercommon>
78 Decoder(Rc<TextDecoderCommon>),
79 /// Algorithms supporting `TextEncoderStream` are implemented in Rust
80 ///
81 /// <https://encoding.spec.whatwg.org/#textencoderstream-encoder>
82 Encoder(Encoder),
83}
84
85impl TransformerType {
86 pub(crate) fn new_from_js_transformer(transformer: &Transformer) -> TransformerType {
87 TransformerType::Js {
88 cancel: RefCell::new(transformer.cancel.clone()),
89 flush: RefCell::new(transformer.flush.clone()),
90 transform: RefCell::new(transformer.transform.clone()),
91 transform_obj: Default::default(),
92 }
93 }
94}
95
96/// <https://streams.spec.whatwg.org/#transformstreamdefaultcontroller>
97#[dom_struct]
98pub struct TransformStreamDefaultController {
99 reflector_: Reflector,
100
101 /// The type of the underlying transformer used. Besides the JS variant,
102 /// there will be other variant(s) for `TextDecoderStream`
103 #[ignore_malloc_size_of = "transformer_type"]
104 transformer_type: TransformerType,
105
106 /// <https://streams.spec.whatwg.org/#TransformStreamDefaultController-stream>
107 stream: MutNullableDom<TransformStream>,
108
109 /// <https://streams.spec.whatwg.org/#transformstreamdefaultcontroller-finishpromise>
110 #[ignore_malloc_size_of = "Rc is hard"]
111 finish_promise: DomRefCell<Option<Rc<Promise>>>,
112}
113
114impl TransformStreamDefaultController {
115 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
116 fn new_inherited(transformer_type: TransformerType) -> TransformStreamDefaultController {
117 TransformStreamDefaultController {
118 reflector_: Reflector::new(),
119 transformer_type,
120 stream: MutNullableDom::new(None),
121 finish_promise: DomRefCell::new(None),
122 }
123 }
124
125 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
126 pub(crate) fn new(
127 global: &GlobalScope,
128 transformer_type: TransformerType,
129 can_gc: CanGc,
130 ) -> DomRoot<TransformStreamDefaultController> {
131 reflect_dom_object(
132 Box::new(TransformStreamDefaultController::new_inherited(
133 transformer_type,
134 )),
135 global,
136 can_gc,
137 )
138 }
139
140 /// Setting the JS object after the heap has settled down.
141 ///
142 /// Note that this has no effect if the transformer type is not `TransformerType::Js`
143 pub(crate) fn set_transform_obj(&self, this_object: SafeHandleObject) {
144 if let TransformerType::Js { transform_obj, .. } = &self.transformer_type {
145 transform_obj.set(*this_object)
146 } else {
147 unreachable!("Non-Js transformer type should not set transform_obj")
148 }
149 }
150
151 pub(crate) fn set_stream(&self, stream: &TransformStream) {
152 self.stream.set(Some(stream));
153 }
154
155 pub(crate) fn get_finish_promise(&self) -> Option<Rc<Promise>> {
156 self.finish_promise.borrow().clone()
157 }
158
159 pub(crate) fn set_finish_promise(&self, promise: Rc<Promise>) {
160 *self.finish_promise.borrow_mut() = Some(promise);
161 }
162
163 /// <https://streams.spec.whatwg.org/#transform-stream-default-controller-perform-transform>
164 pub(crate) fn transform_stream_default_controller_perform_transform(
165 &self,
166 cx: SafeJSContext,
167 global: &GlobalScope,
168 chunk: SafeHandleValue,
169 can_gc: CanGc,
170 ) -> Fallible<Rc<Promise>> {
171 // Let transformPromise be the result of performing controller.[[transformAlgorithm]], passing chunk.
172 let transform_promise = self.perform_transform(cx, global, chunk, can_gc)?;
173
174 // Return the result of reacting to transformPromise with the following rejection steps given the argument r:
175 rooted!(in(*cx) let mut reject_handler = Some(TransformTransformPromiseRejection {
176 controller: Dom::from_ref(self),
177 }));
178
179 let handler = PromiseNativeHandler::new(
180 global,
181 None,
182 reject_handler.take().map(|h| Box::new(h) as Box<_>),
183 can_gc,
184 );
185 let realm = enter_realm(global);
186 let comp = InRealm::Entered(&realm);
187 transform_promise.append_native_handler(&handler, comp, can_gc);
188
189 Ok(transform_promise)
190 }
191
192 pub(crate) fn perform_transform(
193 &self,
194 cx: SafeJSContext,
195 global: &GlobalScope,
196 chunk: SafeHandleValue,
197 can_gc: CanGc,
198 ) -> Fallible<Rc<Promise>> {
199 let result = match &self.transformer_type {
200 // <https://streams.spec.whatwg.org/#set-up-transform-stream-default-controller-from-transformer>
201 TransformerType::Js {
202 transform,
203 transform_obj,
204 ..
205 } => {
206 // Step 5. If transformerDict["transform"] exists, set
207 // transformAlgorithm to an algorithm which takes an argument
208 // chunk and returns the result of invoking
209 // transformerDict["transform"] with argument list « chunk,
210 // controller » and callback this value transformer.
211 let algo = transform.borrow().clone();
212 if let Some(transform) = algo {
213 rooted!(in(*cx) let this_object = transform_obj.get());
214 transform
215 .Call_(
216 &this_object.handle(),
217 chunk,
218 self,
219 ExceptionHandling::Rethrow,
220 can_gc,
221 )
222 .unwrap_or_else(|e| {
223 let p = Promise::new(global, can_gc);
224 p.reject_error(e, can_gc);
225 p
226 })
227 } else {
228 // Step 2. Let transformAlgorithm be the following steps, taking a chunk argument:
229 // Let result be TransformStreamDefaultControllerEnqueue(controller, chunk).
230 // If result is an abrupt completion, return a promise rejected with result.[[Value]].
231 if let Err(error) = self.enqueue(cx, global, chunk, can_gc) {
232 rooted!(in(*cx) let mut error_val = UndefinedValue());
233 error.to_jsval(cx, global, error_val.handle_mut(), can_gc);
234 Promise::new_rejected(global, cx, error_val.handle(), can_gc)
235 } else {
236 // Otherwise, return a promise resolved with undefined.
237 Promise::new_resolved(global, cx, (), can_gc)
238 }
239 }
240 },
241 TransformerType::Decoder(decoder) => {
242 // <https://encoding.spec.whatwg.org/#dom-textdecoderstream>
243 // Step 7. Let transformAlgorithm be an algorithm which takes a
244 // chunk argument and runs the decode and enqueue a chunk
245 // algorithm with this and chunk.
246 decode_and_enqueue_a_chunk(cx, global, chunk, decoder, self, can_gc)
247 // <https://streams.spec.whatwg.org/#transformstream-set-up>
248 // Step 5. Let transformAlgorithmWrapper be an algorithm that runs these steps given a value chunk:
249 // Step 5.1 Let result be the result of running transformAlgorithm given chunk.
250 // Step 5.2 If result is a Promise, then return result.
251 // Note: not applicable, the spec does NOT require deode_and_enqueue_a_chunk() to return a Promise
252 // Step 5.3 Return a promise resolved with undefined.
253 .map(|_| Promise::new_resolved(global, cx, (), can_gc))
254 .unwrap_or_else(|e| {
255 // <https://streams.spec.whatwg.org/#transformstream-set-up>
256 // Step 5.1 If this throws an exception e,
257 let realm = enter_realm(self);
258 let p = Promise::new_in_current_realm((&realm).into(), can_gc);
259 // return a promise rejected with e.
260 p.reject_error(e, can_gc);
261 p
262 })
263 },
264 TransformerType::Encoder(encoder) => {
265 // <https://encoding.spec.whatwg.org/#dom-textencoderstream>
266 // Step 2. Let transformAlgorithm be an algorithm which takes a chunk argument and runs the encode
267 // and enqueue a chunk algorithm with this and chunk.
268 encode_and_enqueue_a_chunk(cx, global, chunk, encoder, self, can_gc)
269 // <https://streams.spec.whatwg.org/#transformstream-set-up>
270 // Step 5. Let transformAlgorithmWrapper be an algorithm that runs these steps given a value chunk:
271 // Step 5.1 Let result be the result of running transformAlgorithm given chunk.
272 // Step 5.2 If result is a Promise, then return result.
273 // Note: not applicable, the spec does NOT require encode_and_enqueue_a_chunk() to return a Promise
274 // Step 5.3 Return a promise resolved with undefined.
275 .map(|_| Promise::new_resolved(global, cx, (), can_gc))
276 .unwrap_or_else(|e| {
277 // <https://streams.spec.whatwg.org/#transformstream-set-up>
278 // Step 5.1 If this throws an exception e,
279 let realm = enter_realm(self);
280 let p = Promise::new_in_current_realm((&realm).into(), can_gc);
281 // return a promise rejected with e.
282 p.reject_error(e, can_gc);
283 p
284 })
285 },
286 };
287
288 Ok(result)
289 }
290
291 pub(crate) fn perform_cancel(
292 &self,
293 cx: SafeJSContext,
294 global: &GlobalScope,
295 chunk: SafeHandleValue,
296 can_gc: CanGc,
297 ) -> Fallible<Rc<Promise>> {
298 let result = match &self.transformer_type {
299 // <https://streams.spec.whatwg.org/#set-up-transform-stream-default-controller-from-transformer>
300 TransformerType::Js {
301 cancel,
302 transform_obj,
303 ..
304 } => {
305 // Step 7. If transformerDict["cancel"] exists, set
306 // cancelAlgorithm to an algorithm which takes an argument
307 // reason and returns the result of invoking
308 // transformerDict["cancel"] with argument list « reason » and
309 // callback this value transformer.
310 let algo = cancel.borrow().clone();
311 if let Some(cancel) = algo {
312 rooted!(in(*cx) let this_object = transform_obj.get());
313 cancel
314 .Call_(
315 &this_object.handle(),
316 chunk,
317 ExceptionHandling::Rethrow,
318 can_gc,
319 )
320 .unwrap_or_else(|e| {
321 let p = Promise::new(global, can_gc);
322 p.reject_error(e, can_gc);
323 p
324 })
325 } else {
326 // Step 4. Let cancelAlgorithm be an algorithm which returns a promise resolved with undefined.
327 Promise::new_resolved(global, cx, (), can_gc)
328 }
329 },
330 TransformerType::Decoder(_) => {
331 // <https://streams.spec.whatwg.org/#transformstream-set-up>
332 // Step 7. Let cancelAlgorithmWrapper be an algorithm that runs these steps given a value reason:
333 // Step 7.1 Let result be the result of running cancelAlgorithm given reason,
334 // if cancelAlgorithm was given, or null otherwise
335 // Note: `TextDecoderStream` does NOT specify a cancel algorithm.
336 // Step 7.2 If result is a Promise, then return result.
337 // Note: Not applicable.
338 // Step 7.3 Return a promise resolved with undefined.
339 Promise::new_resolved(global, cx, (), can_gc)
340 },
341 TransformerType::Encoder(_) => {
342 // <https://streams.spec.whatwg.org/#transformstream-set-up>
343 // Step 7. Let cancelAlgorithmWrapper be an algorithm that runs these steps given a value reason:
344 // Step 7.1 Let result be the result of running cancelAlgorithm given reason,
345 // if cancelAlgorithm was given, or null otherwise
346 // Note: `TextDecoderStream` does NOT specify a cancel algorithm.
347 // Step 7.2 If result is a Promise, then return result.
348 // Note: Not applicable.
349 // Step 7.3 Return a promise resolved with undefined.
350 Promise::new_resolved(global, cx, (), can_gc)
351 },
352 };
353
354 Ok(result)
355 }
356
357 pub(crate) fn perform_flush(
358 &self,
359 cx: SafeJSContext,
360 global: &GlobalScope,
361 can_gc: CanGc,
362 ) -> Fallible<Rc<Promise>> {
363 let result = match &self.transformer_type {
364 // <https://streams.spec.whatwg.org/#set-up-transform-stream-default-controller-from-transformer>
365 TransformerType::Js {
366 flush,
367 transform_obj,
368 ..
369 } => {
370 // Step 6. If transformerDict["flush"] exists, set flushAlgorithm to an
371 // algorithm which returns the result of invoking
372 // transformerDict["flush"] with argument list « controller »
373 // and callback this value transformer.
374 let algo = flush.borrow().clone();
375 if let Some(flush) = algo {
376 rooted!(in(*cx) let this_object = transform_obj.get());
377 flush
378 .Call_(
379 &this_object.handle(),
380 self,
381 ExceptionHandling::Rethrow,
382 can_gc,
383 )
384 .unwrap_or_else(|e| {
385 let p = Promise::new(global, can_gc);
386 p.reject_error(e, can_gc);
387 p
388 })
389 } else {
390 // Step 3. Let flushAlgorithm be an algorithm which returns a promise resolved with undefined.
391 Promise::new_resolved(global, cx, (), can_gc)
392 }
393 },
394 TransformerType::Decoder(decoder) => {
395 // <https://encoding.spec.whatwg.org/#dom-textdecoderstream>
396 // Step 8. Let flushAlgorithm be an algorithm which takes no
397 // arguments and runs the flush and enqueue algorithm with this.
398 flush_and_enqueue(cx, global, decoder, self, can_gc)
399 // <https://streams.spec.whatwg.org/#transformstream-set-up>
400 // Step 6. Let flushAlgorithmWrapper be an algorithm that runs these steps:
401 // Step 6.1 Let result be the result of running flushAlgorithm,
402 // if flushAlgorithm was given, or null otherwise.
403 // Step 6.2 If result is a Promise, then return result.
404 // Note: Not applicable. The spec does NOT require flush_and_enqueue algo to return a Promise
405 // Step 6.3 Return a promise resolved with undefined.
406 .map(|_| Promise::new_resolved(global, cx, (), can_gc))
407 .unwrap_or_else(|e| {
408 // <https://streams.spec.whatwg.org/#transformstream-set-up>
409 // Step 6.1 If this throws an exception e,
410 let realm = enter_realm(self);
411 let p = Promise::new_in_current_realm((&realm).into(), can_gc);
412 // return a promise rejected with e.
413 p.reject_error(e, can_gc);
414 p
415 })
416 },
417 TransformerType::Encoder(encoder) => {
418 // <https://encoding.spec.whatwg.org/#textencoderstream-encoder>
419 // Step 3. Let flushAlgorithm be an algorithm which runs the encode and flush algorithm with this.
420 encode_and_flush(cx, global, encoder, self, can_gc)
421 // <https://streams.spec.whatwg.org/#transformstream-set-up>
422 // Step 6. Let flushAlgorithmWrapper be an algorithm that runs these steps:
423 // Step 6.1 Let result be the result of running flushAlgorithm,
424 // if flushAlgorithm was given, or null otherwise.
425 // Step 6.2 If result is a Promise, then return result.
426 // Note: Not applicable. The spec does NOT require encode_and_flush algo to return a Promise
427 // Step 6.3 Return a promise resolved with undefined.
428 .map(|_| Promise::new_resolved(global, cx, (), can_gc))
429 .unwrap_or_else(|e| {
430 // <https://streams.spec.whatwg.org/#transformstream-set-up>
431 // Step 6.1 If this throws an exception e,
432 let realm = enter_realm(self);
433 let p = Promise::new_in_current_realm((&realm).into(), can_gc);
434 // return a promise rejected with e.
435 p.reject_error(e, can_gc);
436 p
437 })
438 },
439 };
440
441 Ok(result)
442 }
443
444 /// <https://streams.spec.whatwg.org/#transform-stream-default-controller-enqueue>
445 #[allow(unsafe_code)]
446 pub(crate) fn enqueue(
447 &self,
448 cx: SafeJSContext,
449 global: &GlobalScope,
450 chunk: SafeHandleValue,
451 can_gc: CanGc,
452 ) -> Fallible<()> {
453 // Let stream be controller.[[stream]].
454 let stream = self.stream.get().expect("stream is null");
455
456 // Let readableController be stream.[[readable]].[[controller]].
457 let readable = stream.get_readable();
458 let readable_controller = readable.get_default_controller();
459
460 // If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController)
461 // is false, throw a TypeError exception.
462 if !readable_controller.can_close_or_enqueue() {
463 return Err(Error::Type(
464 "ReadableStreamDefaultControllerCanCloseOrEnqueue is false".to_owned(),
465 ));
466 }
467
468 // Let enqueueResult be ReadableStreamDefaultControllerEnqueue(readableController, chunk).
469 // If enqueueResult is an abrupt completion,
470 if let Err(error) = readable_controller.enqueue(cx, chunk, can_gc) {
471 // Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, enqueueResult.[[Value]]).
472 rooted!(in(*cx) let mut rooted_error = UndefinedValue());
473 error
474 .clone()
475 .to_jsval(cx, global, rooted_error.handle_mut(), can_gc);
476 stream.error_writable_and_unblock_write(cx, global, rooted_error.handle(), can_gc);
477
478 // Throw stream.[[readable]].[[storedError]].
479 unsafe {
480 if !JS_IsExceptionPending(*cx) {
481 rooted!(in(*cx) let mut stored_error = UndefinedValue());
482 readable.get_stored_error(stored_error.handle_mut());
483
484 JS_SetPendingException(
485 *cx,
486 stored_error.handle().into(),
487 ExceptionStackBehavior::Capture,
488 );
489 }
490 }
491 return Err(error);
492 }
493
494 // Let backpressure be ! ReadableStreamDefaultControllerHasBackpressure(readableController).
495 let backpressure = readable_controller.has_backpressure();
496
497 // If backpressure is not stream.[[backpressure]],
498 if backpressure != stream.get_backpressure() {
499 // Assert: backpressure is true.
500 assert!(backpressure);
501
502 // Perform ! TransformStreamSetBackpressure(stream, true).
503 stream.set_backpressure(global, true, can_gc);
504 }
505 Ok(())
506 }
507
508 /// <https://streams.spec.whatwg.org/#transform-stream-default-controller-error>
509 pub(crate) fn error(
510 &self,
511 cx: SafeJSContext,
512 global: &GlobalScope,
513 reason: SafeHandleValue,
514 can_gc: CanGc,
515 ) {
516 // Perform ! TransformStreamError(controller.[[stream]], e).
517 self.stream
518 .get()
519 .expect("stream is undefined")
520 .error(cx, global, reason, can_gc);
521 }
522
523 /// <https://streams.spec.whatwg.org/#transform-stream-default-controller-clear-algorithms>
524 pub(crate) fn clear_algorithms(&self) {
525 if let TransformerType::Js {
526 cancel,
527 flush,
528 transform,
529 ..
530 } = &self.transformer_type
531 {
532 // Set controller.[[transformAlgorithm]] to undefined.
533 transform.replace(None);
534
535 // Set controller.[[flushAlgorithm]] to undefined.
536 flush.replace(None);
537
538 // Set controller.[[cancelAlgorithm]] to undefined.
539 cancel.replace(None);
540 }
541 }
542
543 /// <https://streams.spec.whatwg.org/#transform-stream-default-controller-terminate>
544 pub(crate) fn terminate(&self, cx: SafeJSContext, global: &GlobalScope, can_gc: CanGc) {
545 // Let stream be controller.[[stream]].
546 let stream = self.stream.get().expect("stream is null");
547
548 // Let readableController be stream.[[readable]].[[controller]].
549 let readable = stream.get_readable();
550 let readable_controller = readable.get_default_controller();
551
552 // Perform ! ReadableStreamDefaultControllerClose(readableController).
553 readable_controller.close(can_gc);
554
555 // Let error be a TypeError exception indicating that the stream has been terminated.
556 let error = Error::Type("stream has been terminated".to_owned());
557
558 // Perform ! TransformStreamErrorWritableAndUnblockWrite(stream, error).
559 rooted!(in(*cx) let mut rooted_error = UndefinedValue());
560 error.to_jsval(cx, global, rooted_error.handle_mut(), can_gc);
561 stream.error_writable_and_unblock_write(cx, global, rooted_error.handle(), can_gc);
562 }
563}
564
565#[allow(non_snake_case)]
566impl TransformStreamDefaultControllerMethods<crate::DomTypeHolder>
567 for TransformStreamDefaultController
568{
569 /// <https://streams.spec.whatwg.org/#ts-default-controller-desired-size>
570 fn GetDesiredSize(&self) -> Option<f64> {
571 // Let readableController be this.[[stream]].[[readable]].[[controller]].
572 let readable_controller = self
573 .stream
574 .get()
575 .expect("stream is null")
576 .get_readable()
577 .get_default_controller();
578
579 // Return ! ReadableStreamDefaultControllerGetDesiredSize(readableController).
580 readable_controller.get_desired_size()
581 }
582
583 /// <https://streams.spec.whatwg.org/#ts-default-controller-enqueue>
584 fn Enqueue(&self, cx: SafeJSContext, chunk: SafeHandleValue, can_gc: CanGc) -> Fallible<()> {
585 // Perform ? TransformStreamDefaultControllerEnqueue(this, chunk).
586 self.enqueue(cx, &self.global(), chunk, can_gc)
587 }
588
589 /// <https://streams.spec.whatwg.org/#ts-default-controller-error>
590 fn Error(&self, cx: SafeJSContext, reason: SafeHandleValue, can_gc: CanGc) -> Fallible<()> {
591 // Perform ? TransformStreamDefaultControllerError(this, e).
592 self.error(cx, &self.global(), reason, can_gc);
593 Ok(())
594 }
595
596 /// <https://streams.spec.whatwg.org/#ts-default-controller-terminate>
597 fn Terminate(&self, can_gc: CanGc) -> Fallible<()> {
598 // Perform ? TransformStreamDefaultControllerTerminate(this).
599 self.terminate(GlobalScope::get_cx(), &self.global(), can_gc);
600 Ok(())
601 }
602}