Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use new Streams algorithms #35

Merged
merged 3 commits into from
Sep 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
SHELL=/bin/bash

index.html: index.bs
curl https://api.csswg.org/bikeshed/ -F file=@index.bs -F force=1 > index.html
@ (HTTP_STATUS=$$(curl https://api.csswg.org/bikeshed/ \
--output index.html \
--write-out "%{http_code}" \
--header "Accept: text/plain, text/html" \
-F die-on=warning \
-F file=@index.bs) && \
[[ "$$HTTP_STATUS" -eq "200" ]]) || ( \
echo ""; cat index.html; echo ""; \
rm -f index.html; \
exit 22 \
);
96 changes: 31 additions & 65 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -92,26 +92,6 @@ A <dfn>compression context</dfn> is the internal state maintained by a compressi
* A `gzip` stream may only contain one "member".
* It is an error if there is additional input data after the end of the "member".

# Interface Mixin `GenericTransformStream` # {#generic-transform-stream}

The {{GenericTransformStream}} interface mixin represents the concept of a transform stream in IDL. It is not a TransformStream, though it has the same interface and it delegates to one.

<pre class="idl">
interface mixin GenericTransformStream {
readonly attribute ReadableStream readable;
readonly attribute WritableStream writable;
};
</pre>

An object that includes {{GenericTransformStream}} has an associated <dfn>transform</dfn> of type TransformStream.

## Attributes ## {#outgoing-stream-attributes}

: <dfn attribute for="GenericTransformStream">readable</dfn>
:: The `readable` attribute's getter, when invoked, must return this object's transform \[[readable]].
: <dfn attribute for="GenericTransformStream">writable</dfn>
:: The `writable` attribute's getter, when invoked, must return this object's transform \[[writable]].

# Interface `CompressionStream` # {#compression-stream}

<pre class="idl">
Expand All @@ -124,33 +104,26 @@ CompressionStream includes GenericTransformStream;

A {{CompressionStream}} has an associated <dfn for=CompressionStream>format</dfn> and <a>compression context</a> <dfn for=CompressionStream>context</dfn>.

The {{CompressionStream}}(*format*) constructor, when invoked, must run these steps:
1. If *format* is unsupported in CompressionStream, then throw a TypeError.
1. Let *cs* be a new CompressionStream object.
1. Set *cs*'s <a for=CompressionStream>format</a> to *format*.
1. Let *startAlgorithm* be an algorithm that takes no arguments and returns nothing.
1. Let *transformAlgorithm* be an algorithm which takes a *chunk* argument and runs the <a>compress and enqueue a chunk</a> algorithm with *cs* and *chunk*.
1. Let *flushAlgorithm* be an algorithm which takes no argument and runs the <a>compress flush and enqueue</a> algorithm with *cs*.
1. Let *transform* be the result of calling <a abstract-op>CreateTransformStream</a>(*startAlgorithm*, *transformAlgorithm*, *flushAlgorithm*).
1. Set *cs*'s <a>transform</a> to *transform*.
1. Return *cs*.

The <dfn>compress and enqueue a chunk</dfn> algorithm, given a CompressionStream object *cs* and a *chunk*, runs these steps:
1. If *chunk* is not a {{BufferSource}} type, then return <a>a promise rejected with</a> a TypeError.
The <dfn constructor for=CompressionStream lt="CompressionStream(format)"><code>new CompressionStream(|format|)</code></dfn> steps are:
1. If *format* is unsupported in {{CompressionStream}}, then throw a {{TypeError}}.
1. Set [=this=]'s <a for=CompressionStream>format</a> to *format*.
1. Let *transformAlgorithm* be an algorithm which takes a *chunk* argument and runs the <a>compress and enqueue a chunk</a> algorithm with [=this=] and *chunk*.
1. Let *flushAlgorithm* be an algorithm which takes no argument and runs the <a>compress flush and enqueue</a> algorithm with [=this=].
1. Set [=this=]'s [=GenericTransformStream/transform=] to the result of [=TransformStream/creating=] a {{TransformStream}} with <a for=TransformStream/create><var ignore>transformAlgorithm</var></a> set to *transformAlgorithm* and <a for=TransformStream/create><var ignore>flushAlgorithm</var></a> set to *flushAlgorithm*.

The <dfn>compress and enqueue a chunk</dfn> algorithm, given a {{CompressionStream}} object *cs* and a *chunk*, runs these steps:
1. If *chunk* is not a {{BufferSource}} type, then throw a {{TypeError}}.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the streams standard converts exceptions to rejections in algorithms.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new wrappers do, specifically for TransformStreams, because all the ones on the web platform are synchronous, and I wanted to make it easy. It's not super-consistent though, e.g. for writable streams I made writeAlgorithm and closeAlgorithm return promises because that's what NativeFS does... Probably I should be more uniform.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I missed that. It would be nice to be more uniform, but I'd rather avoid adding more microtasks if possible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is all about spec-land convenience, I can just branch on the return type :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't end up making this uniform on the Streams side, oops. Something to follow up on perhaps, especially if anyone else wants to make more complicated transform streams in the future.

1. Let *buffer* be the result of compressing *chunk* with *cs*'s <a for=CompressionStream>format</a> and <a for=CompressionStream>context</a>.
1. Let *controller* be *cs*'s transform.\[[TransformStreamController]].
1. If *buffer* is empty, return <a>a promise resolved with</a> undefined.
1. Split *buffer* into one or more non-empty pieces and convert them into Uint8Arrays.
1. For each Uint8Array *array*, call <a abstract-op>TransformStreamDefaultControllerEnqueue</a>(*controller*, *array*).
1. Return <a>a promise resolved with</a> undefined.
1. If *buffer* is empty, return.
1. Split *buffer* into one or more non-empty pieces and convert them into {{Uint8Array}}s.
1. For each {{Uint8Array}} *array*, [=TransformStream/enqueue=] *array* in *cs*'s [=GenericTransformStream/transform=].

The <dfn>compress flush and enqueue</dfn> algorithm, which handles the end of data from the input ReadableStream object, given a CompressionStream object *cs*, runs these steps:
The <dfn>compress flush and enqueue</dfn> algorithm, which handles the end of data from the input {{ReadableStream}} object, given a {{CompressionStream}} object *cs*, runs these steps:

1. Let *buffer* be the result of compressing an empty input with *cs*'s <a for=CompressionStream>format</a> and <a for=CompressionStream>context</a>, with the finish flag.
1. If *buffer* is empty, return <a>a promise resolved with</a> undefined.
1. Split *buffer* into one or more non-empty pieces and convert them into Uint8Arrays.
1. For each Uint8Array *array*, call <a abstract-op>TransformStreamDefaultControllerEnqueue</a>(*controller*, *array*).
1. Return <a>a promise resolved with</a> undefined.
1. If *buffer* is empty, return.
1. Split *buffer* into one or more non-empty pieces and convert them into {{Uint8Array}}s.
1. For each {{Uint8Array}} *array*, [=TransformStream/enqueue=] *array* in *cs*'s [=GenericTransformStream/transform=].


# Interface `DecompressionStream` # {#decompression-stream}
Expand All @@ -165,34 +138,27 @@ DecompressionStream includes GenericTransformStream;

A {{DecompressionStream}} has an associated <dfn for=DecompressionStream>format</dfn> and <a>compression context</a> <dfn for=DecompressionStream>context</dfn>.

The {{DecompressionStream}}(*format*) constructor, when invoked, must run these steps:
1. If *format* is unsupported in DecompressionStream, then throw a TypeError.
1. Let *ds* be a new DecompressionStream object.
1. Set *ds*'s <a for=DecompressionStream>format</a> to *format*.
1. Let *startAlgorithm* be an algorithm that takes no arguments and returns nothing.
The <dfn constructor for=DecompressionStream lt="DecompressionStream(format)"><code>new DecompressionStream(|format|)</code></dfn> steps are:
1. If *format* is unsupported in {{DecompressionStream}}, then throw a {{TypeError}}.
1. Set [=this=]'s <a for=DecompressionStream>format</a> to *format*.
1. Let *transformAlgorithm* be an algorithm which takes a *chunk* argument and runs the <a>decompress and enqueue a chunk</a> algorithm with *ds* and *chunk*.
1. Let *flushAlgorithm* be an algorithm which takes no argument and runs the <a>decompress flush and enqueue</a> algorithm with *ds*.
1. Let *transform* be the result of calling <a abstract-op>CreateTransformStream</a>(*startAlgorithm*, *transformAlgorithm*, *flushAlgorithm*).
1. Set *ds*'s <a>transform</a> to *transform*.
1. Return *ds*.
1. Set [=this=]'s [=GenericTransformStream/transform=] to the result of [=TransformStream/creating=] a {{TransformStream}} with <a for=TransformStream/create><var ignore>transformAlgorithm</var></a> set to *transformAlgorithm* and <a for=TransformStream/create><var ignore>flushAlgorithm</var></a> set to *flushAlgorithm*.

The <dfn>decompress and enqueue a chunk</dfn> algorithm, given a DecompressionStream object *ds* and a *chunk*, runs these steps:
1. If *chunk* is not a {{BufferSource}} type, then return <a>a promise rejected with</a> a TypeError.
1. Let *buffer* be the result of decompressing *chunk* with *ds*'s <a for=DecompressionStream>format</a> and <a for=DecompressionStream>context</a>. If this results in an error, then return <a>a promise rejected with</a> a TypeError.
1. Let *controller* be *ds*'s <a>transform</a>.\[[TransformStreamController]].
1. If *buffer* is empty, return <a>a promise resolved with</a> undefined.
1. Split *buffer* into one or more non-empty pieces and convert them into Uint8Arrays.
1. For each Uint8Array *array*, call <a abstract-op>TransformStreamDefaultControllerEnqueue</a>(*controller*, *array*).
1. Return <a>a promise resolved with</a> undefined.
The <dfn>decompress and enqueue a chunk</dfn> algorithm, given a {{DecompressionStream}} object *ds* and a *chunk*, runs these steps:
1. If *chunk* is not a {{BufferSource}} type, then throw a {{TypeError}}.
1. Let *buffer* be the result of decompressing *chunk* with *ds*'s <a for=DecompressionStream>format</a> and <a for=DecompressionStream>context</a>. If this results in an error, then throw a {{TypeError}}.
1. If *buffer* is empty, return.
1. Split *buffer* into one or more non-empty pieces and convert them into {{Uint8Array}}s.
1. For each {{Uint8Array}} *array*, [=TransformStream/enqueue=] *array* in *ds*'s [=GenericTransformStream/transform=].

The <dfn>decompress flush and enqueue</dfn> algorithm, which handles the end of data from the input ReadableStream object, given a DecompressionStream object *ds*, runs these steps:
The <dfn>decompress flush and enqueue</dfn> algorithm, which handles the end of data from the input {{ReadableStream}} object, given a {{DecompressionStream}} object *ds*, runs these steps:

1. Let *buffer* be the result of decompressing an empty input with *ds*'s <a for=DecompressionStream>format</a> and <a for=DecompressionStream>context</a>, with the finish flag.
1. If the end of the compressed input has not been reached, return <a>a promise rejected with</a> a TypeError.
1. If *buffer* is empty, return <a>a promise resolved with</a> undefined.
1. Split *buffer* into one or more non-empty pieces and convert them into Uint8Arrays.
1. For each Uint8Array *array*, call <a abstract-op>TransformStreamDefaultControllerEnqueue</a>(*controller*, *array*).
1. Return <a>a promise resolved with</a> undefined.
1. If the end of the compressed input has not been reached, then throw a {{TypeError}}.
1. If *buffer* is empty, return.
1. Split *buffer* into one or more non-empty pieces and convert them into {{Uint8Array}}s.
1. For each {{Uint8Array}} *array*, [=TransformStream/enqueue=] *array* in *ds*'s [=GenericTransformStream/transform=].


# Privacy and Security Considerations # {#privacy-security}
Expand Down
Loading