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}