Skip to main content

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