servo/components/script/dom/readablestreamgenericreader.rs
Taym Haddadi f3f4cc5500
Script implement TransformStream and TransformStreamDefaultController (#36739)
Part of https://github.com/servo/servo/issues/34676

---------

Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>
Signed-off-by: Taym <haddadi.taym@gmail.com>
Co-authored-by: gterzian <2792687+gterzian@users.noreply.github.com>
2025-05-08 08:45:57 +00:00

175 lines
6.7 KiB
Rust

/* 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::rc::Rc;
use js::jsval::UndefinedValue;
use js::rust::HandleValue as SafeHandleValue;
use super::readablestream::ReaderType;
use super::types::ReadableStream;
use crate::dom::bindings::error::{Error, ErrorToJsval, Fallible};
use crate::dom::bindings::reflector::DomGlobal;
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::readablestreambyobreader::ReadableStreamBYOBReader;
use crate::dom::readablestreamdefaultreader::ReadableStreamDefaultReader;
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
/// <https://streams.spec.whatwg.org/#readablestreamgenericreader>
pub(crate) trait ReadableStreamGenericReader {
/// <https://streams.spec.whatwg.org/#readable-stream-reader-generic-initialize>
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
fn generic_initialize(&self, global: &GlobalScope, stream: &ReadableStream, can_gc: CanGc) {
// Set reader.[[stream]] to stream.
self.set_stream(Some(stream));
// Set stream.[[reader]] to reader.
let reader_type = if let Some(default_reader) = self.as_default_reader() {
ReaderType::Default(MutNullableDom::new(Some(default_reader)))
} else if let Some(byob_reader) = self.as_byob_reader() {
ReaderType::BYOB(MutNullableDom::new(Some(byob_reader)))
} else {
unreachable!("Reader must be either Default or BYOB.");
};
stream.set_reader(Some(reader_type));
if stream.is_readable() {
// If stream.[[state]] is "readable
// Set reader.[[closedPromise]] to a new promise.
self.set_closed_promise(Promise::new(global, can_gc));
} else if stream.is_closed() {
// Otherwise, if stream.[[state]] is "closed",
// Set reader.[[closedPromise]] to a promise resolved with undefined.
let cx = GlobalScope::get_cx();
self.set_closed_promise(Promise::new_resolved(global, cx, (), can_gc));
} else {
// Assert: stream.[[state]] is "errored"
assert!(stream.is_errored());
// Set reader.[[closedPromise]] to a promise rejected with stream.[[storedError]].
let cx = GlobalScope::get_cx();
rooted!(in(*cx) let mut error = UndefinedValue());
stream.get_stored_error(error.handle_mut());
self.set_closed_promise(Promise::new_rejected(global, cx, error.handle(), can_gc));
// Set reader.[[closedPromise]].[[PromiseIsHandled]] to true
self.get_closed_promise().set_promise_is_handled();
}
}
/// <https://streams.spec.whatwg.org/#readable-stream-reader-generic-cancel>
fn reader_generic_cancel(
&self,
cx: SafeJSContext,
global: &GlobalScope,
reason: SafeHandleValue,
can_gc: CanGc,
) -> Rc<Promise> {
// Let stream be reader.[[stream]].
let stream = self.get_stream();
// Assert: stream is not undefined.
let stream =
stream.expect("Reader should have a stream when generic cancel is called into.");
// Return ! ReadableStreamCancel(stream, reason).
stream.cancel(cx, global, reason, can_gc)
}
/// <https://streams.spec.whatwg.org/#readable-stream-reader-generic-release>
fn generic_release(&self, can_gc: CanGc) -> Fallible<()> {
// Let stream be reader.[[stream]].
// Assert: stream is not undefined.
assert!(self.get_stream().is_some());
if let Some(stream) = self.get_stream() {
// Assert: stream.[[reader]] is reader.
if self.as_default_reader().is_some() {
assert!(stream.has_default_reader());
} else {
assert!(stream.has_byob_reader());
}
if stream.is_readable() {
// If stream.[[state]] is "readable", reject reader.[[closedPromise]] with a TypeError exception.
self.get_closed_promise().reject_error(
Error::Type("stream state is not readable".to_owned()),
can_gc,
);
} else {
// Otherwise, set reader.[[closedPromise]] to a promise rejected with a TypeError exception.
let cx = GlobalScope::get_cx();
rooted!(in(*cx) let mut error = UndefinedValue());
Error::Type("Cannot release lock due to stream state.".to_owned()).to_jsval(
cx,
&stream.global(),
error.handle_mut(),
can_gc,
);
self.set_closed_promise(Promise::new_rejected(
&stream.global(),
cx,
error.handle(),
can_gc,
));
}
// Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
self.get_closed_promise().set_promise_is_handled();
// Perform ! stream.[[controller]].[[ReleaseSteps]]().
stream.perform_release_steps()?;
// Set stream.[[reader]] to undefined.
stream.set_reader(None);
// Set reader.[[stream]] to undefined.
self.set_stream(None);
}
Ok(())
}
/// <https://streams.spec.whatwg.org/#generic-reader-closed>
fn closed(&self) -> Rc<Promise> {
self.get_closed_promise()
}
// <https://streams.spec.whatwg.org/#generic-reader-cancel>
fn generic_cancel(
&self,
cx: SafeJSContext,
global: &GlobalScope,
reason: SafeHandleValue,
can_gc: CanGc,
) -> Rc<Promise> {
if self.get_stream().is_none() {
// If this.[[stream]] is undefined,
// return a promise rejected with a TypeError exception.
let promise = Promise::new(global, can_gc);
promise.reject_error(Error::Type("stream is undefined".to_owned()), can_gc);
promise
} else {
// Return ! ReadableStreamReaderGenericCancel(this, reason).
self.reader_generic_cancel(cx, global, reason, can_gc)
}
}
fn set_stream(&self, stream: Option<&ReadableStream>);
fn get_stream(&self) -> Option<DomRoot<ReadableStream>>;
fn set_closed_promise(&self, promise: Rc<Promise>);
fn get_closed_promise(&self) -> Rc<Promise>;
fn as_default_reader(&self) -> Option<&ReadableStreamDefaultReader> {
None
}
fn as_byob_reader(&self) -> Option<&ReadableStreamBYOBReader> {
None
}
}