script/dom/
readablestreamgenericreader.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 http://mozilla.org/MPL/2.0/. */
4
5use std::rc::Rc;
6
7use js::jsval::UndefinedValue;
8use js::rust::HandleValue as SafeHandleValue;
9
10use super::readablestream::ReaderType;
11use super::types::ReadableStream;
12use crate::dom::bindings::error::{Error, ErrorToJsval, Fallible};
13use crate::dom::bindings::reflector::DomGlobal;
14use crate::dom::bindings::root::{DomRoot, MutNullableDom};
15use crate::dom::globalscope::GlobalScope;
16use crate::dom::promise::Promise;
17use crate::dom::readablestreambyobreader::ReadableStreamBYOBReader;
18use crate::dom::readablestreamdefaultreader::ReadableStreamDefaultReader;
19use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
20
21/// <https://streams.spec.whatwg.org/#readablestreamgenericreader>
22pub(crate) trait ReadableStreamGenericReader {
23    /// <https://streams.spec.whatwg.org/#readable-stream-reader-generic-initialize>
24    #[cfg_attr(crown, allow(crown::unrooted_must_root))]
25    fn generic_initialize(&self, global: &GlobalScope, stream: &ReadableStream, can_gc: CanGc) {
26        // Set reader.[[stream]] to stream.
27        self.set_stream(Some(stream));
28
29        // Set stream.[[reader]] to reader.
30        let reader_type = if let Some(default_reader) = self.as_default_reader() {
31            ReaderType::Default(MutNullableDom::new(Some(default_reader)))
32        } else if let Some(byob_reader) = self.as_byob_reader() {
33            ReaderType::BYOB(MutNullableDom::new(Some(byob_reader)))
34        } else {
35            unreachable!("Reader must be either Default or BYOB.");
36        };
37        stream.set_reader(Some(reader_type));
38
39        if stream.is_readable() {
40            // If stream.[[state]] is "readable
41            // Set reader.[[closedPromise]] to a new promise.
42            self.set_closed_promise(Promise::new(global, can_gc));
43        } else if stream.is_closed() {
44            // Otherwise, if stream.[[state]] is "closed",
45            // Set reader.[[closedPromise]] to a promise resolved with undefined.
46            let cx = GlobalScope::get_cx();
47            self.set_closed_promise(Promise::new_resolved(global, cx, (), can_gc));
48        } else {
49            // Assert: stream.[[state]] is "errored"
50            assert!(stream.is_errored());
51
52            // Set reader.[[closedPromise]] to a promise rejected with stream.[[storedError]].
53            let cx = GlobalScope::get_cx();
54            rooted!(in(*cx) let mut error = UndefinedValue());
55            stream.get_stored_error(error.handle_mut());
56            self.set_closed_promise(Promise::new_rejected(global, cx, error.handle(), can_gc));
57
58            // Set reader.[[closedPromise]].[[PromiseIsHandled]] to true
59            self.get_closed_promise().set_promise_is_handled();
60        }
61    }
62
63    /// <https://streams.spec.whatwg.org/#readable-stream-reader-generic-cancel>
64    fn reader_generic_cancel(
65        &self,
66        cx: SafeJSContext,
67        global: &GlobalScope,
68        reason: SafeHandleValue,
69        can_gc: CanGc,
70    ) -> Rc<Promise> {
71        // Let stream be reader.[[stream]].
72        let stream = self.get_stream();
73
74        // Assert: stream is not undefined.
75        let stream =
76            stream.expect("Reader should have a stream when generic cancel is called into.");
77
78        // Return ! ReadableStreamCancel(stream, reason).
79        stream.cancel(cx, global, reason, can_gc)
80    }
81
82    /// <https://streams.spec.whatwg.org/#readable-stream-reader-generic-release>
83    fn generic_release(&self, can_gc: CanGc) -> Fallible<()> {
84        // Let stream be reader.[[stream]].
85
86        // Assert: stream is not undefined.
87        assert!(self.get_stream().is_some());
88
89        if let Some(stream) = self.get_stream() {
90            // Assert: stream.[[reader]] is reader.
91            if self.as_default_reader().is_some() {
92                assert!(stream.has_default_reader());
93            } else {
94                assert!(stream.has_byob_reader());
95            }
96
97            if stream.is_readable() {
98                // If stream.[[state]] is "readable", reject reader.[[closedPromise]] with a TypeError exception.
99                self.get_closed_promise().reject_error(
100                    Error::Type("stream state is not readable".to_owned()),
101                    can_gc,
102                );
103            } else {
104                // Otherwise, set reader.[[closedPromise]] to a promise rejected with a TypeError exception.
105                let cx = GlobalScope::get_cx();
106                rooted!(in(*cx) let mut error = UndefinedValue());
107                Error::Type("Cannot release lock due to stream state.".to_owned()).to_jsval(
108                    cx,
109                    &stream.global(),
110                    error.handle_mut(),
111                    can_gc,
112                );
113
114                self.set_closed_promise(Promise::new_rejected(
115                    &stream.global(),
116                    cx,
117                    error.handle(),
118                    can_gc,
119                ));
120            }
121            // Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
122            self.get_closed_promise().set_promise_is_handled();
123
124            // Perform ! stream.[[controller]].[[ReleaseSteps]]().
125            stream
126                .perform_release_steps()
127                .expect("Stream should have a controller");
128
129            // Set stream.[[reader]] to undefined.
130            stream.set_reader(None);
131            // Set reader.[[stream]] to undefined.
132            self.set_stream(None);
133        }
134        Ok(())
135    }
136
137    /// <https://streams.spec.whatwg.org/#generic-reader-closed>
138    fn closed(&self) -> Rc<Promise> {
139        self.get_closed_promise()
140    }
141
142    // <https://streams.spec.whatwg.org/#generic-reader-cancel>
143    fn generic_cancel(
144        &self,
145        cx: SafeJSContext,
146        global: &GlobalScope,
147        reason: SafeHandleValue,
148        can_gc: CanGc,
149    ) -> Rc<Promise> {
150        if self.get_stream().is_none() {
151            // If this.[[stream]] is undefined,
152            // return a promise rejected with a TypeError exception.
153            let promise = Promise::new(global, can_gc);
154            promise.reject_error(Error::Type("stream is undefined".to_owned()), can_gc);
155            promise
156        } else {
157            // Return ! ReadableStreamReaderGenericCancel(this, reason).
158            self.reader_generic_cancel(cx, global, reason, can_gc)
159        }
160    }
161
162    fn set_stream(&self, stream: Option<&ReadableStream>);
163
164    fn get_stream(&self) -> Option<DomRoot<ReadableStream>>;
165
166    fn set_closed_promise(&self, promise: Rc<Promise>);
167
168    fn get_closed_promise(&self) -> Rc<Promise>;
169
170    fn as_default_reader(&self) -> Option<&ReadableStreamDefaultReader> {
171        None
172    }
173
174    fn as_byob_reader(&self) -> Option<&ReadableStreamBYOBReader> {
175        None
176    }
177}