| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| use std::cell::Cell; |
| use std::collections::VecDeque; |
| use std::mem; |
| use std::rc::Rc; |
| |
| use dom_struct::dom_struct; |
| use js::gc::MutableHandle; |
| use js::jsapi::Heap; |
| use js::jsval::{JSVal, UndefinedValue}; |
| use js::rust::{HandleObject as SafeHandleObject, HandleValue as SafeHandleValue}; |
| |
| use super::bindings::reflector::reflect_dom_object; |
| use super::bindings::root::MutNullableDom; |
| use super::readablebytestreamcontroller::ReadableByteStreamController; |
| use super::types::ReadableStreamDefaultController; |
| use crate::dom::bindings::cell::DomRefCell; |
| use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultReaderBinding::{ |
| ReadableStreamDefaultReaderMethods, ReadableStreamReadResult, |
| }; |
| use crate::dom::bindings::error::{Error, ErrorToJsval, Fallible}; |
| use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto}; |
| use crate::dom::bindings::root::{Dom, DomRoot}; |
| use crate::dom::bindings::trace::RootedTraceableBox; |
| use crate::dom::defaultteereadrequest::DefaultTeeReadRequest; |
| use crate::dom::globalscope::GlobalScope; |
| use crate::dom::promise::Promise; |
| use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler}; |
| use crate::dom::readablestream::{ReadableStream, get_read_promise_bytes, get_read_promise_done}; |
| use crate::dom::readablestreamgenericreader::ReadableStreamGenericReader; |
| use crate::realms::{InRealm, enter_realm}; |
| use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; |
| |
| type ReadAllBytesSuccessSteps = dyn Fn(&[u8]); |
| type ReadAllBytesFailureSteps = dyn Fn(SafeJSContext, SafeHandleValue); |
| |
| impl js::gc::Rootable for ReadLoopFulFillmentHandler {} |
| |
| /// <https://streams.spec.whatwg.org/#read-loop> |
| #[derive(Clone, JSTraceable, MallocSizeOf)] |
| #[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] |
| struct ReadLoopFulFillmentHandler { |
| #[ignore_malloc_size_of = "Rc is hard"] |
| #[no_trace] |
| success_steps: Rc<ReadAllBytesSuccessSteps>, |
| |
| #[ignore_malloc_size_of = "Rc is hard"] |
| #[no_trace] |
| failure_steps: Rc<ReadAllBytesFailureSteps>, |
| |
| reader: Dom<ReadableStreamDefaultReader>, |
| |
| #[ignore_malloc_size_of = "Rc is hard"] |
| bytes: Rc<DomRefCell<Vec<u8>>>, |
| } |
| |
| impl Callback for ReadLoopFulFillmentHandler { |
| #[cfg_attr(crown, allow(crown::unrooted_must_root))] |
| fn callback(&self, cx: SafeJSContext, v: SafeHandleValue, realm: InRealm, can_gc: CanGc) { |
| let global = self.reader.global(); |
| let is_done = match get_read_promise_done(cx, &v, can_gc) { |
| Ok(is_done) => is_done, |
| Err(err) => { |
| self.reader |
| .release(can_gc) |
| .expect("Releasing the reader should succeed"); |
| rooted!(in(*cx) let mut v = UndefinedValue()); |
| err.to_jsval(cx, &global, v.handle_mut(), can_gc); |
| (self.failure_steps)(cx, v.handle()); |
| return; |
| }, |
| }; |
| |
| if is_done { |
| // <https://streams.spec.whatwg.org/#ref-for-read-request-close-steps%E2%91%A6> |
| // Call successSteps with bytes. |
| (self.success_steps)(&self.bytes.borrow()); |
| self.reader |
| .release(can_gc) |
| .expect("Releasing the reader should succeed"); |
| } else { |
| // <https://streams.spec.whatwg.org/#ref-for-read-request-chunk-steps%E2%91%A6> |
| let chunk = match get_read_promise_bytes(cx, &v, can_gc) { |
| Ok(chunk) => chunk, |
| Err(err) => { |
| // If chunk is not a Uint8Array object, call failureSteps with a TypeError and abort these steps. |
| rooted!(in(*cx) let mut v = UndefinedValue()); |
| err.to_jsval(cx, &global, v.handle_mut(), can_gc); |
| (self.failure_steps)(cx, v.handle()); |
| self.reader |
| .release(can_gc) |
| .expect("Releasing the reader should succeed"); |
| return; |
| }, |
| }; |
| |
| // Append the bytes represented by chunk to bytes. |
| self.bytes.borrow_mut().extend_from_slice(&chunk); |
| |
| // Read-loop given reader, bytes, successSteps, and failureSteps. |
| rooted!(in(*cx) let mut this = Some(self.clone())); |
| read_loop( |
| &global, |
| this.handle_mut(), |
| Box::new(ReadLoopRejectionHandler { |
| failure_steps: self.failure_steps.clone(), |
| }), |
| realm, |
| can_gc, |
| ); |
| } |
| } |
| } |
| |
| #[derive(Clone, JSTraceable, MallocSizeOf)] |
| /// <https://streams.spec.whatwg.org/#readablestreamdefaultreader-read-all-bytes> |
| struct ReadLoopRejectionHandler { |
| #[ignore_malloc_size_of = "Rc is hard"] |
| #[no_trace] |
| failure_steps: Rc<ReadAllBytesFailureSteps>, |
| } |
| |
| impl Callback for ReadLoopRejectionHandler { |
| /// <https://streams.spec.whatwg.org/#ref-for-read-request-error-steps%E2%91%A6> |
| fn callback(&self, cx: SafeJSContext, v: SafeHandleValue, _realm: InRealm, _can_gc: CanGc) { |
| // Call failureSteps with e. |
| (self.failure_steps)(cx, v); |
| } |
| } |
| |
| /// <https://streams.spec.whatwg.org/#read-loop> |
| fn read_loop( |
| global: &GlobalScope, |
| mut fulfillment_handler: MutableHandle<Option<ReadLoopFulFillmentHandler>>, |
| rejection_handler: Box<ReadLoopRejectionHandler>, |
| realm: InRealm, |
| can_gc: CanGc, |
| ) { |
| // Let readRequest be a new read request with the following items: |
| // Note: the custom read request logic is implemented |
| // using a native promise handler attached to the promise returned by `Read` |
| // (which internally uses a default read request). |
| |
| // Perform ! ReadableStreamDefaultReaderRead(reader, readRequest). |
| let read_promise = fulfillment_handler |
| .as_ref() |
| .expect("Fulfillment handler should be some.") |
| .reader |
| .Read(can_gc); |
| |
| let handler = PromiseNativeHandler::new( |
| global, |
| fulfillment_handler.take().map(|h| Box::new(h) as Box<_>), |
| Some(rejection_handler), |
| can_gc, |
| ); |
| read_promise.append_native_handler(&handler, realm, can_gc); |
| } |
| |
| /// <https://streams.spec.whatwg.org/#read-request> |
| #[derive(Clone, JSTraceable, MallocSizeOf)] |
| pub(crate) enum ReadRequest { |
| /// <https://streams.spec.whatwg.org/#default-reader-read> |
| Read(#[ignore_malloc_size_of = "Rc is hard"] Rc<Promise>), |
| /// <https://streams.spec.whatwg.org/#ref-for-read-request%E2%91%A2> |
| DefaultTee { |
| tee_read_request: Dom<DefaultTeeReadRequest>, |
| }, |
| } |
| |
| impl ReadRequest { |
| /// <https://streams.spec.whatwg.org/#read-request-chunk-steps> |
| pub(crate) fn chunk_steps(&self, chunk: RootedTraceableBox<Heap<JSVal>>, can_gc: CanGc) { |
| match self { |
| ReadRequest::Read(promise) => { |
| // chunk steps, given chunk |
| // Resolve promise with «[ "value" → chunk, "done" → false ]». |
| promise.resolve_native( |
| &ReadableStreamReadResult { |
| done: Some(false), |
| value: chunk, |
| }, |
| can_gc, |
| ); |
| }, |
| ReadRequest::DefaultTee { tee_read_request } => { |
| tee_read_request.enqueue_chunk_steps(chunk); |
| }, |
| } |
| } |
| |
| /// <https://streams.spec.whatwg.org/#read-request-close-steps> |
| pub(crate) fn close_steps(&self, can_gc: CanGc) { |
| match self { |
| ReadRequest::Read(promise) => { |
| // close steps |
| // Resolve promise with «[ "value" → undefined, "done" → true ]». |
| let result = RootedTraceableBox::new(Heap::default()); |
| result.set(UndefinedValue()); |
| promise.resolve_native( |
| &ReadableStreamReadResult { |
| done: Some(true), |
| value: result, |
| }, |
| can_gc, |
| ); |
| }, |
| ReadRequest::DefaultTee { tee_read_request } => { |
| tee_read_request.close_steps(can_gc); |
| }, |
| } |
| } |
| |
| /// <https://streams.spec.whatwg.org/#read-request-error-steps> |
| pub(crate) fn error_steps(&self, e: SafeHandleValue, can_gc: CanGc) { |
| match self { |
| ReadRequest::Read(promise) => { |
| // error steps, given e |
| // Reject promise with e. |
| promise.reject_native(&e, can_gc) |
| }, |
| ReadRequest::DefaultTee { tee_read_request } => { |
| tee_read_request.error_steps(); |
| }, |
| } |
| } |
| } |
| |
| /// The rejection handler for |
| /// <https://streams.spec.whatwg.org/#readable-stream-tee> |
| #[derive(Clone, JSTraceable, MallocSizeOf)] |
| #[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] |
| struct ClosedPromiseRejectionHandler { |
| branch_1_controller: Dom<ReadableStreamDefaultController>, |
| branch_2_controller: Dom<ReadableStreamDefaultController>, |
| #[ignore_malloc_size_of = "Rc"] |
| canceled_1: Rc<Cell<bool>>, |
| #[ignore_malloc_size_of = "Rc"] |
| canceled_2: Rc<Cell<bool>>, |
| #[ignore_malloc_size_of = "Rc"] |
| cancel_promise: Rc<Promise>, |
| } |
| |
| impl Callback for ClosedPromiseRejectionHandler { |
| /// Continuation of <https://streams.spec.whatwg.org/#readable-stream-default-controller-call-pull-if-needed> |
| /// Upon rejection of `reader.closedPromise` with reason `r``, |
| fn callback(&self, _cx: SafeJSContext, v: SafeHandleValue, _realm: InRealm, can_gc: CanGc) { |
| let branch_1_controller = &self.branch_1_controller; |
| let branch_2_controller = &self.branch_2_controller; |
| |
| // Perform ! ReadableStreamDefaultControllerError(branch_1.[[controller]], r). |
| branch_1_controller.error(v, can_gc); |
| // Perform ! ReadableStreamDefaultControllerError(branch_2.[[controller]], r). |
| branch_2_controller.error(v, can_gc); |
| |
| // If canceled_1 is false or canceled_2 is false, resolve cancelPromise with undefined. |
| if !self.canceled_1.get() || !self.canceled_2.get() { |
| self.cancel_promise.resolve_native(&(), can_gc); |
| } |
| } |
| } |
| |
| /// <https://streams.spec.whatwg.org/#readablestreamdefaultreader> |
| #[dom_struct] |
| pub(crate) struct ReadableStreamDefaultReader { |
| reflector_: Reflector, |
| |
| /// <https://streams.spec.whatwg.org/#readablestreamgenericreader-stream> |
| stream: MutNullableDom<ReadableStream>, |
| |
| read_requests: DomRefCell<VecDeque<ReadRequest>>, |
| |
| /// <https://streams.spec.whatwg.org/#readablestreamgenericreader-closedpromise> |
| #[ignore_malloc_size_of = "Rc is hard"] |
| closed_promise: DomRefCell<Rc<Promise>>, |
| } |
| |
| impl ReadableStreamDefaultReader { |
| fn new_with_proto( |
| global: &GlobalScope, |
| proto: Option<SafeHandleObject>, |
| can_gc: CanGc, |
| ) -> DomRoot<ReadableStreamDefaultReader> { |
| reflect_dom_object_with_proto( |
| Box::new(ReadableStreamDefaultReader::new_inherited(global, can_gc)), |
| global, |
| proto, |
| can_gc, |
| ) |
| } |
| |
| fn new_inherited(global: &GlobalScope, can_gc: CanGc) -> ReadableStreamDefaultReader { |
| ReadableStreamDefaultReader { |
| reflector_: Reflector::new(), |
| stream: MutNullableDom::new(None), |
| read_requests: DomRefCell::new(Default::default()), |
| closed_promise: DomRefCell::new(Promise::new(global, can_gc)), |
| } |
| } |
| |
| pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<ReadableStreamDefaultReader> { |
| reflect_dom_object( |
| Box::new(Self::new_inherited(global, can_gc)), |
| global, |
| can_gc, |
| ) |
| } |
| |
| /// <https://streams.spec.whatwg.org/#set-up-readable-stream-default-reader> |
| pub(crate) fn set_up( |
| &self, |
| stream: &ReadableStream, |
| global: &GlobalScope, |
| can_gc: CanGc, |
| ) -> Fallible<()> { |
| // If ! IsReadableStreamLocked(stream) is true, throw a TypeError exception. |
| if stream.is_locked() { |
| return Err(Error::Type("stream is locked".to_owned())); |
| } |
| // Perform ! ReadableStreamReaderGenericInitialize(reader, stream). |
| |
| self.generic_initialize(global, stream, can_gc); |
| |
| // Set reader.[[readRequests]] to a new empty list. |
| self.read_requests.borrow_mut().clear(); |
| |
| Ok(()) |
| } |
| |
| /// <https://streams.spec.whatwg.org/#readable-stream-close> |
| pub(crate) fn close(&self, can_gc: CanGc) { |
| // Resolve reader.[[closedPromise]] with undefined. |
| self.closed_promise.borrow().resolve_native(&(), can_gc); |
| // If reader implements ReadableStreamDefaultReader, |
| // Let readRequests be reader.[[readRequests]]. |
| let mut read_requests = self.take_read_requests(); |
| // Set reader.[[readRequests]] to an empty list. |
| // For each readRequest of readRequests, |
| for request in read_requests.drain(0..) { |
| // Perform readRequest’s close steps. |
| request.close_steps(can_gc); |
| } |
| } |
| |
| /// <https://streams.spec.whatwg.org/#readable-stream-add-read-request> |
| pub(crate) fn add_read_request(&self, read_request: &ReadRequest) { |
| self.read_requests |
| .borrow_mut() |
| .push_back(read_request.clone()); |
| } |
| |
| /// <https://streams.spec.whatwg.org/#readable-stream-get-num-read-requests> |
| pub(crate) fn get_num_read_requests(&self) -> usize { |
| self.read_requests.borrow().len() |
| } |
| |
| /// <https://streams.spec.whatwg.org/#readable-stream-error> |
| pub(crate) fn error(&self, e: SafeHandleValue, can_gc: CanGc) { |
| // Reject reader.[[closedPromise]] with e. |
| self.closed_promise.borrow().reject_native(&e, can_gc); |
| |
| // Set reader.[[closedPromise]].[[PromiseIsHandled]] to true. |
| self.closed_promise.borrow().set_promise_is_handled(); |
| |
| // Perform ! ReadableStreamDefaultReaderErrorReadRequests(reader, e). |
| self.error_read_requests(e, can_gc); |
| } |
| |
| /// The removal steps of <https://streams.spec.whatwg.org/#readable-stream-fulfill-read-request> |
| pub(crate) fn remove_read_request(&self) -> ReadRequest { |
| self.read_requests |
| .borrow_mut() |
| .pop_front() |
| .expect("Reader must have read request when remove is called into.") |
| } |
| |
| /// <https://streams.spec.whatwg.org/#abstract-opdef-readablestreamdefaultreaderrelease> |
| pub(crate) fn release(&self, can_gc: CanGc) -> Fallible<()> { |
| // Perform ! ReadableStreamReaderGenericRelease(reader). |
| self.generic_release(can_gc)?; |
| // Let e be a new TypeError exception. |
| let cx = GlobalScope::get_cx(); |
| rooted!(in(*cx) let mut error = UndefinedValue()); |
| Error::Type("Reader is released".to_owned()).to_jsval( |
| cx, |
| &self.global(), |
| error.handle_mut(), |
| can_gc, |
| ); |
| |
| // Perform ! ReadableStreamDefaultReaderErrorReadRequests(reader, e). |
| self.error_read_requests(error.handle(), can_gc); |
| Ok(()) |
| } |
| |
| fn take_read_requests(&self) -> VecDeque<ReadRequest> { |
| mem::take(&mut *self.read_requests.borrow_mut()) |
| } |
| |
| /// <https://streams.spec.whatwg.org/#abstract-opdef-readablestreamdefaultreadererrorreadrequests> |
| fn error_read_requests(&self, rval: SafeHandleValue, can_gc: CanGc) { |
| // step 1 |
| let mut read_requests = self.take_read_requests(); |
| |
| // step 2 & 3 |
| for request in read_requests.drain(0..) { |
| request.error_steps(rval, can_gc); |
| } |
| } |
| |
| /// <https://streams.spec.whatwg.org/#readable-stream-default-reader-read> |
| pub(crate) fn read(&self, cx: SafeJSContext, read_request: &ReadRequest, can_gc: CanGc) { |
| // Let stream be reader.[[stream]]. |
| |
| // Assert: stream is not undefined. |
| assert!(self.stream.get().is_some()); |
| |
| let stream = self.stream.get().unwrap(); |
| |
| // Set stream.[[disturbed]] to true. |
| stream.set_is_disturbed(true); |
| // If stream.[[state]] is "closed", perform readRequest’s close steps. |
| if stream.is_closed() { |
| read_request.close_steps(can_gc); |
| } else if stream.is_errored() { |
| // Otherwise, if stream.[[state]] is "errored", |
| // perform readRequest’s error steps given stream.[[storedError]]. |
| let cx = GlobalScope::get_cx(); |
| rooted!(in(*cx) let mut error = UndefinedValue()); |
| stream.get_stored_error(error.handle_mut()); |
| read_request.error_steps(error.handle(), can_gc); |
| } else { |
| // Otherwise |
| // Assert: stream.[[state]] is "readable". |
| assert!(stream.is_readable()); |
| // Perform ! stream.[[controller]].[[PullSteps]](readRequest). |
| stream.perform_pull_steps(cx, read_request, can_gc); |
| } |
| } |
| |
| /// <https://streams.spec.whatwg.org/#ref-for-readablestreamgenericreader-closedpromise%E2%91%A1> |
| pub(crate) fn append_native_handler_to_closed_promise( |
| &self, |
| branch_1: &ReadableStream, |
| branch_2: &ReadableStream, |
| canceled_1: Rc<Cell<bool>>, |
| canceled_2: Rc<Cell<bool>>, |
| cancel_promise: Rc<Promise>, |
| can_gc: CanGc, |
| ) { |
| let branch_1_controller = branch_1.get_default_controller(); |
| |
| let branch_2_controller = branch_2.get_default_controller(); |
| |
| let global = self.global(); |
| let handler = PromiseNativeHandler::new( |
| &global, |
| None, |
| Some(Box::new(ClosedPromiseRejectionHandler { |
| branch_1_controller: Dom::from_ref(&branch_1_controller), |
| branch_2_controller: Dom::from_ref(&branch_2_controller), |
| canceled_1, |
| canceled_2, |
| cancel_promise, |
| })), |
| can_gc, |
| ); |
| |
| let realm = enter_realm(&*global); |
| let comp = InRealm::Entered(&realm); |
| |
| self.closed_promise |
| .borrow() |
| .append_native_handler(&handler, comp, can_gc); |
| } |
| |
| /// <https://streams.spec.whatwg.org/#readablestreamdefaultreader-read-all-bytes> |
| pub(crate) fn read_all_bytes( |
| &self, |
| cx: SafeJSContext, |
| global: &GlobalScope, |
| success_steps: Rc<ReadAllBytesSuccessSteps>, |
| failure_steps: Rc<ReadAllBytesFailureSteps>, |
| realm: InRealm, |
| can_gc: CanGc, |
| ) { |
| // To read all bytes from a ReadableStreamDefaultReader reader, |
| // given successSteps, which is an algorithm accepting a byte sequence, |
| // and failureSteps, which is an algorithm accepting a JavaScript value: |
| // read-loop given reader, a new byte sequence, successSteps, and failureSteps. |
| // Note: read-loop done using native promise handlers. |
| rooted!(in(*cx) let mut fulfillment_handler = Some(ReadLoopFulFillmentHandler { |
| success_steps, |
| failure_steps: failure_steps.clone(), |
| reader: Dom::from_ref(self), |
| bytes: Rc::new(DomRefCell::new(Vec::new())), |
| })); |
| let rejection_handler = Box::new(ReadLoopRejectionHandler { failure_steps }); |
| read_loop( |
| global, |
| fulfillment_handler.handle_mut(), |
| rejection_handler, |
| realm, |
| can_gc, |
| ); |
| } |
| |
| /// step 3 of <https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerprocessreadrequestsusingqueue> |
| pub(crate) fn process_read_requests( |
| &self, |
| cx: SafeJSContext, |
| controller: DomRoot<ReadableByteStreamController>, |
| can_gc: CanGc, |
| ) -> Fallible<()> { |
| // While reader.[[readRequests]] is not empty, |
| while !self.read_requests.borrow().is_empty() { |
| // If controller.[[queueTotalSize]] is 0, return. |
| if controller.get_queue_total_size() == 0.0 { |
| return Ok(()); |
| } |
| |
| // Let readRequest be reader.[[readRequests]][0]. |
| // Remove entry from controller.[[queue]]. |
| let read_request = self.remove_read_request(); |
| |
| // Perform ! ReadableByteStreamControllerFillReadRequestFromQueue(controller, readRequest). |
| controller.fill_read_request_from_queue(cx, &read_request, can_gc)?; |
| } |
| Ok(()) |
| } |
| } |
| |
| impl ReadableStreamDefaultReaderMethods<crate::DomTypeHolder> for ReadableStreamDefaultReader { |
| /// <https://streams.spec.whatwg.org/#default-reader-constructor> |
| fn Constructor( |
| global: &GlobalScope, |
| proto: Option<SafeHandleObject>, |
| can_gc: CanGc, |
| stream: &ReadableStream, |
| ) -> Fallible<DomRoot<Self>> { |
| let reader = Self::new_with_proto(global, proto, can_gc); |
| |
| // Perform ? SetUpReadableStreamDefaultReader(this, stream). |
| Self::set_up(&reader, stream, global, can_gc)?; |
| |
| Ok(reader) |
| } |
| |
| /// <https://streams.spec.whatwg.org/#default-reader-read> |
| fn Read(&self, can_gc: CanGc) -> Rc<Promise> { |
| let cx = GlobalScope::get_cx(); |
| // If this.[[stream]] is undefined, return a promise rejected with a TypeError exception. |
| if self.stream.get().is_none() { |
| rooted!(in(*cx) let mut error = UndefinedValue()); |
| Error::Type("stream is undefined".to_owned()).to_jsval( |
| cx, |
| &self.global(), |
| error.handle_mut(), |
| can_gc, |
| ); |
| return Promise::new_rejected(&self.global(), cx, error.handle(), can_gc); |
| } |
| // Let promise be a new promise. |
| let promise = Promise::new(&self.global(), can_gc); |
| |
| // Let readRequest be a new read request with the following items: |
| // chunk steps, given chunk |
| // Resolve promise with «[ "value" → chunk, "done" → false ]». |
| // |
| // close steps |
| // Resolve promise with «[ "value" → undefined, "done" → true ]». |
| // |
| // error steps, given e |
| // Reject promise with e. |
| |
| // Rooting(unrooted_must_root): the read request contains only a promise, |
| // which does not need to be rooted, |
| // as it is safely managed natively via an Rc. |
| let read_request = ReadRequest::Read(promise.clone()); |
| |
| // Perform ! ReadableStreamDefaultReaderRead(this, readRequest). |
| self.read(cx, &read_request, can_gc); |
| |
| // Return promise. |
| promise |
| } |
| |
| /// <https://streams.spec.whatwg.org/#default-reader-release-lock> |
| fn ReleaseLock(&self, can_gc: CanGc) -> Fallible<()> { |
| if self.stream.get().is_none() { |
| // Step 1: If this.[[stream]] is undefined, return. |
| return Ok(()); |
| } |
| |
| // Step 2: Perform !ReadableStreamDefaultReaderRelease(this). |
| self.release(can_gc) |
| } |
| |
| /// <https://streams.spec.whatwg.org/#generic-reader-closed> |
| fn Closed(&self) -> Rc<Promise> { |
| self.closed() |
| } |
| |
| /// <https://streams.spec.whatwg.org/#generic-reader-cancel> |
| fn Cancel(&self, cx: SafeJSContext, reason: SafeHandleValue, can_gc: CanGc) -> Rc<Promise> { |
| self.generic_cancel(cx, &self.global(), reason, can_gc) |
| } |
| } |
| |
| impl ReadableStreamGenericReader for ReadableStreamDefaultReader { |
| fn get_closed_promise(&self) -> Rc<Promise> { |
| self.closed_promise.borrow().clone() |
| } |
| |
| fn set_closed_promise(&self, promise: Rc<Promise>) { |
| *self.closed_promise.borrow_mut() = promise; |
| } |
| |
| fn set_stream(&self, stream: Option<&ReadableStream>) { |
| self.stream.set(stream); |
| } |
| |
| fn get_stream(&self) -> Option<DomRoot<ReadableStream>> { |
| self.stream.get() |
| } |
| |
| fn as_default_reader(&self) -> Option<&ReadableStreamDefaultReader> { |
| Some(self) |
| } |
| } |