Script: Implement TextDecoderStream (#38112)

This PR implements the `TextDecoderStream`. Other than introducing the
necessary mod and webidl files corresponding to `TextDecoderStream`,
this PR also involves some changes in `TextDecoder` and
`TrasnformStream`:

- The common part that can be shared between `TextDecoder` and
`TextDecoderStream` are extracted into a separate type
`script::dom::textdecodercommon::TextDecoderCommon`. This type could
probably use a different name because there is an interface called
`TextDecoderCommon` in the spec
(https://encoding.spec.whatwg.org/#textdecodercommon) which just gets
included in `TextDecoder` and `TextDecoderStream`.
- The three algorithms in `TransformStream` (`cancel`, `flush`, and
`transform`) all have become `enum` that has a `Js` variant for a JS
function object and a `Native` variant for a rust trait object. Whether
the cancel algorithm needs this enum type is debatable as I did not find
any interface in the spec that explicitly sets the cancel algorithm.

Testing: Existing WPT tests `tests/wpt/tests/encoding/stream` should be
sufficient
Fixes: #37723

---------

Signed-off-by: minghuaw <michael.wu1107@gmail.com>
Signed-off-by: minghuaw <wuminghua7@huawei.com>
Signed-off-by: Minghua Wu <michael.wu1107@gmail.com>
This commit is contained in:
minghuaw 2025-07-29 12:18:15 +08:00 committed by GitHub
parent 25822920cf
commit 554b2da1ad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 797 additions and 752 deletions

View file

@ -36,6 +36,7 @@ use crate::dom::countqueuingstrategy::{extract_high_water_mark, extract_size_alg
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::readablestream::{ReadableStream, create_readable_stream};
use crate::dom::transformstreamdefaultcontroller::TransformerType;
use crate::dom::types::PromiseNativeHandler;
use crate::dom::underlyingsourcecontainer::UnderlyingSourceType;
use crate::dom::writablestream::create_writable_stream;
@ -436,6 +437,60 @@ impl TransformStream {
)
}
/// Creates and set up the newly created transform stream following
/// <https://streams.spec.whatwg.org/#transformstream-set-up>
pub(crate) fn set_up(
&self,
cx: SafeJSContext,
global: &GlobalScope,
transformer_type: TransformerType,
can_gc: CanGc,
) -> Fallible<()> {
// Step1. Let writableHighWaterMark be 1.
let writable_high_water_mark = 1.0;
// Step 2. Let writableSizeAlgorithm be an algorithm that returns 1.
let writable_size_algorithm = extract_size_algorithm(&Default::default(), can_gc);
// Step 3. Let readableHighWaterMark be 0.
let readable_high_water_mark = 0.0;
// Step 4. Let readableSizeAlgorithm be an algorithm that returns 1.
let readable_size_algorithm = extract_size_algorithm(&Default::default(), can_gc);
// Step 5. Let transformAlgorithmWrapper be an algorithm that runs these steps given a value chunk:
// Step 6. Let flushAlgorithmWrapper be an algorithm that runs these steps:
// Step 7. Let cancelAlgorithmWrapper be an algorithm that runs these steps given a value reason:
// NOTE: These steps are implemented in `TransformStreamDefaultController::new`
// Step 8. Let startPromise be a promise resolved with undefined.
let start_promise = Promise::new_resolved(global, cx, (), can_gc);
// Step 9. Perform ! InitializeTransformStream(stream, startPromise,
// writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark,
// readableSizeAlgorithm).
self.initialize(
cx,
global,
start_promise.clone(),
writable_high_water_mark,
writable_size_algorithm,
readable_high_water_mark,
readable_size_algorithm,
can_gc,
)?;
// Step 10. Let controller be a new TransformStreamDefaultController.
let controller = TransformStreamDefaultController::new(global, transformer_type, can_gc);
// Step 11. Perform ! SetUpTransformStreamDefaultController(stream,
// controller, transformAlgorithmWrapper, flushAlgorithmWrapper,
// cancelAlgorithmWrapper).
self.set_up_transform_stream_default_controller(&controller);
Ok(())
}
pub(crate) fn get_controller(&self) -> DomRoot<TransformStreamDefaultController> {
self.controller.get().expect("controller is not set")
}
@ -568,7 +623,8 @@ impl TransformStream {
can_gc: CanGc,
) {
// Let controller be a new TransformStreamDefaultController.
let controller = TransformStreamDefaultController::new(global, transformer, can_gc);
let transformer_type = TransformerType::new_from_js_transformer(transformer);
let controller = TransformStreamDefaultController::new(global, transformer_type, can_gc);
// Let transformAlgorithm be the following steps, taking a chunk argument:
// Let result be TransformStreamDefaultControllerEnqueue(controller, chunk).
@ -892,6 +948,7 @@ impl TransformStream {
}
}
#[allow(non_snake_case)]
impl TransformStreamMethods<crate::DomTypeHolder> for TransformStream {
/// <https://streams.spec.whatwg.org/#ts-constructor>
#[allow(unsafe_code)]