Skip to content

Commit a03c53a

Browse files
authored
Add async value iterators and async iterator arguments
Closes #800.
1 parent 74ae345 commit a03c53a

File tree

1 file changed

+98
-21
lines changed

1 file changed

+98
-21
lines changed

index.bs

Lines changed: 98 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4293,28 +4293,55 @@ An [=interface=] can be declared to be asynchronously iterable by using an
42934293
(matching <emu-nt><a href="#prod-AsyncIterable">AsyncIterable</a></emu-nt>) in the body of the
42944294
[=interface=].
42954295

4296-
<pre highlight="webidl" class="syntax">
4296+
<!-- TODO: add highlight="webidl" after idlparser gets updated -->
4297+
<pre class="syntax">
42974298
interface interface_identifier {
4299+
async iterable&lt;value_type&gt;;
4300+
async iterable&lt;value_type&gt;(/* arguments... */);
42984301
async iterable&lt;key_type, value_type&gt;;
4302+
async iterable&lt;key_type, value_type&gt;(/* arguments... */);
42994303
};
43004304
</pre>
43014305

43024306
Objects that [=implement=] an [=interface=] that is declared to be asynchronously iterable support
43034307
being iterated over asynchronously to obtain a sequence of values.
43044308

4305-
Note: In the ECMAScript language binding, an interface that is asynchronously iterable will have
4306-
<code class="idl">entries</code>, <code class="idl">keys</code>, <code class="idl">values</code>,
4307-
and {{@@asyncIterator}} properties on its [=interface prototype object=].
4309+
If a single type parameter is given, then the interface has a
4310+
<dfn export>value asynchronously iterable declaration</dfn> and asynchronously provides values of the
4311+
specified type. If two type parameters are given, then the interface has a
4312+
<dfn export>pair asynchronously iterable declaration</dfn> and asynchronously provides
4313+
[=value pairs=] with the given types.
4314+
4315+
If given, an [=asynchronously iterable declaration=]'s arguments (matching
4316+
<emu-nt><a href="#prod-ArgumentList">ArgumentList</a></emu-nt>) must all be [=optional arguments=].
4317+
4318+
<div class="note">
4319+
In the ECMAScript language binding, an interface that is asynchronously iterable will have
4320+
{{@@asyncIterator}} and <code class="idl">values</code> properties on its
4321+
[=interface prototype object=]. If the interface has a
4322+
[=pair asynchronously iterable declaration=], it will additionally have
4323+
<code class="idl">entries</code> and <code class="idl">keys</code> properties. All of these
4324+
methods can be passed optional arguments, which correspond to the argument list in the
4325+
[=asynchronously iterable declaration=], and are processed by the
4326+
[=asynchronous iterator initialization steps=], if any exist.
4327+
4328+
With this in mind, the requirement that all arguments be optional ensures that, in the
4329+
ECMAScript binding, <code>for</code>-<code>await</code>-<code>of</code> can work directly on
4330+
instances of the interface, since <code>for</code>-<code>await</code>-<code>of</code> calls the
4331+
{{@@asyncIterator}} method with no arguments.
4332+
</div>
43084333

43094334
Prose accompanying an [=interface=] with an [=asynchronously iterable declaration=] must define a
43104335
<dfn id="dfn-get-the-next-iteration-result" export>get the next iteration result</dfn> algorithm.
43114336
This algorithm receives the instance of the [=interface=] that is being iterated, as well as the
43124337
async iterator itself (which can be useful for storing state).
43134338
It must return a {{Promise}} that either rejects, resolves with undefined to signal the end of the
4314-
iteration, or resolves with a tuple containing two elements:
4339+
iteration, or resolves with one of the following:
43154340

4316-
1. a value of the first type given in the declaration;
4317-
1. a value of the second type given in the declaration.
4341+
: for [=value asynchronously iterable declarations=]:
4342+
:: a value of the type given in the declaration;
4343+
: for [=pair asynchronously iterable declarations=]:
4344+
:: a tuple containing a value of the first type given in the declaration, and a value of the second type given in the declaration.
43184345

43194346
The prose may also define an <dfn export>asynchronous iterator return</dfn> algorithm. This
43204347
algorithm receives the instance of the [=interface=] that is being iterated, the async iterator
@@ -4333,8 +4360,8 @@ but if you are creating an API that needs such capabilities, please
43334360
<a href="https://github.com/heycam/webidl/issues/new?title=Enhancement%20request%20for%20Async%20Iterables">file an issue</a>.
43344361

43354362
The prose may also define <dfn export>asynchronous iterator initialization steps</dfn>. These
4336-
receive the instance of the [=interface=] being iterated, as well as the newly-created
4337-
iterator object.
4363+
receive the instance of the [=interface=] being iterated, the newly-created iterator object, and a
4364+
[=list=] of IDL values representing the arguments passed, if any.
43384365

43394366
[=Interfaces=] with an [=asynchronously iterable declaration=] must not have any
43404367
[=interface members=] named "<code>entries</code>", "<code>keys</code>", or "<code>values</code>",
@@ -4443,7 +4470,13 @@ When they are, the effect will be as you would expect.
44434470

44444471
<pre class="grammar" id="prod-AsyncIterable">
44454472
AsyncIterable :
4446-
"async" "iterable" "&lt;" TypeWithExtendedAttributes "," TypeWithExtendedAttributes "&gt;" ";"
4473+
"async" "iterable" "&lt;" TypeWithExtendedAttributes OptionalType "&gt;" OptionalArgumentList ";"
4474+
</pre>
4475+
4476+
<pre class="grammar" id="prod-OptionalArgumentList">
4477+
OptionalArgumentList :
4478+
"(" ArgumentList ")"
4479+
ε
44474480
</pre>
44484481

44494482

@@ -12290,75 +12323,113 @@ and the string "<code> Iterator</code>".
1229012323
To <dfn>define the asynchronous iteration methods</dfn> of [=interface=] |definition| on
1229112324
|target|, given [=Realm=] |realm|, run the following steps:
1229212325

12293-
1. If |definition| does not have an an [=asynchronously iterable declaration=], then return.
12326+
1. If |definition| does not have an an [=asynchronously iterable declaration=] (of either
12327+
sort), then return.
1229412328
1. Assert: |definition| does not have an [=indexed property getter=] or an
1229512329
[=iterable declaration=].
12296-
1. Define the {{@@asyncIterator}} and <code class="idl">entries</code> methods:
12297-
1. Let |steps| be the following series of steps:
12330+
1. If |definition| has a [=pair asynchronously iterable declaration=], then define the
12331+
{{@@asyncIterator}} and <code class="idl">entries</code> methods:
12332+
1. Let |steps| be the following series of steps, given function argument values |args|:
1229812333
1. Let |esValue| be [=?=] [$ToObject$](<emu-val>this</emu-val> value).
1229912334
1. If |esValue| [=is a platform object=], then [=perform a security check=], passing
1230012335
|esValue|, "<code>@@asyncIterator</code>", and "<code>method</code>".
1230112336
1. If |esValue| does not [=implement=] |definition|, then [=ECMAScript/throw=] a
1230212337
{{ECMAScript/TypeError}}.
1230312338
1. Let |idlObject| be the IDL [=interface type=] value that represents a reference to
1230412339
|esValue|.
12340+
1. Let |idlArgs| be the result of
12341+
[=converting arguments for an asynchronous iterator method=] given |args|.
1230512342
1. Let |iterator| be a newly created [=default asynchronous iterator object=] for
1230612343
|definition| with |idlObject| as its
1230712344
[=default asynchronous iterator object/target=], "<code>key+value</code>" as its
1230812345
[=default asynchronous iterator object/kind=], and
1230912346
[=default asynchronous iterator object/is finished=] set to false.
1231012347
1. Run the [=asynchronous iterator initialization steps=] for |definition| with
12311-
|idlObject| and |iterator|, if any such steps exist.
12348+
|idlObject|, |iterator|, and |idlArgs|, if any such steps exist.
1231212349
1. Return |iterator|.
1231312350
1. Let |F| be [=!=] [$CreateBuiltinFunction$](|steps|, « », |realm|).
1231412351
1. Perform [=!=] [$SetFunctionName$](|F|, "<code>entries</code>").
1231512352
1. Perform [=!=] [$SetFunctionLength$](|F|, 0).
1231612353
1. Perform [=!=] [$CreateMethodProperty$](|target|, {{@@asyncIterator}}, |F|).
1231712354
1. Perform [=!=] [$CreateDataProperty$](|target|, "<code>entries</code>", |F|).
12318-
1. Define the <code class="idl">keys</code> method:
12319-
1. Let |steps| be the following series of steps:
12355+
1. If |definition| has a [=pair asynchronously iterable declaration=], then define the
12356+
<code class="idl">keys</code> method:
12357+
1. Let |steps| be the following series of steps, given function argument values |args|:
1232012358
1. Let |esValue| be [=?=] [$ToObject$](<emu-val>this</emu-val> value).
1232112359
1. If |esValue| [=is a platform object=], then [=perform a security check=], passing
1232212360
|esValue|, "<code>keys</code>", and "<code>method</code>".
1232312361
1. If |esValue| does not [=implement=] |definition|, then [=ECMAScript/throw=] a
1232412362
{{ECMAScript/TypeError}}.
1232512363
1. Let |idlObject| be the IDL [=interface type=] value that represents a reference to
1232612364
|esValue|.
12365+
1. Let |idlArgs| be the result of
12366+
[=converting arguments for an asynchronous iterator method=] given |args|.
1232712367
1. Let |iterator| be a newly created [=default asynchronous iterator object=] for
1232812368
|definition| with |idlObject| as its
1232912369
[=default asynchronous iterator object/target=], "<code>key</code>" as its
1233012370
[=default asynchronous iterator object/kind=], and
1233112371
[=default asynchronous iterator object/is finished=] set to false.
1233212372
1. Run the [=asynchronous iterator initialization steps=] for |definition| with
12333-
|idlObject| and |iterator|, if any such steps exist.
12373+
|idlObject|, |iterator|, and |idlArgs|, if any such steps exist.
1233412374
1. Return |iterator|.
1233512375
1. Let |F| be [=!=] [$CreateBuiltinFunction$](|steps|, « », |realm|).
1233612376
1. Perform [=!=] [$SetFunctionName$](|F|, "<code>keys</code>").
1233712377
1. Perform [=!=] [$SetFunctionLength$](|F|, 0).
1233812378
1. Perform [=!=] [$CreateDataProperty$](|target|, "<code>keys</code>", |F|).
12339-
1. Define the <code class="idl">values</code> method:
12340-
1. Let |steps| be the following series of steps:
12379+
1. Define the <code class="idl">values</code>, and possibly {{@@asyncIterator}}, methods:
12380+
1. Let |steps| be the following series of steps, given function argument values |args|:
1234112381
1. Let |esValue| be [=?=] [$ToObject$](<emu-val>this</emu-val> value).
1234212382
1. If |esValue| [=is a platform object=], then [=perform a security check=], passing
1234312383
|esValue|, "<code>values</code>", and "<code>method</code>".
1234412384
1. If |esValue| does not [=implement=] |definition|, then [=ECMAScript/throw=] a
1234512385
{{ECMAScript/TypeError}}.
1234612386
1. Let |idlObject| be the IDL [=interface type=] value that represents a reference to
1234712387
|esValue|.
12388+
1. Let |idlArgs| be the result of
12389+
[=converting arguments for an asynchronous iterator method=] given |args|.
1234812390
1. Let |iterator| be a newly created [=default asynchronous iterator object=] for
1234912391
|definition| with |idlObject| as its
1235012392
[=default asynchronous iterator object/target=], "<code>value</code>" as its
1235112393
[=default asynchronous iterator object/kind=], and
1235212394
[=default asynchronous iterator object/is finished=] set to false.
1235312395
1. Run the [=asynchronous iterator initialization steps=] for |definition| with
12354-
|idlObject| and |iterator|, if any such steps exist.
12396+
|idlObject|, |iterator|, and |idlArgs|, if any such steps exist.
1235512397
1. Return |iterator|.
1235612398
1. Let |F| be [=!=] [$CreateBuiltinFunction$](|steps|, « », |realm|).
1235712399
1. Perform [=!=] [$SetFunctionName$](|F|, "<code>values</code>").
1235812400
1. Perform [=!=] [$SetFunctionLength$](|F|, 0).
1235912401
1. Perform [=!=] [$CreateDataProperty$](|target|, "<code>values</code>", |F|).
12402+
1. If |definition| has a [=value asynchronously iterable declaration=], then perform [=!=]
12403+
[$CreateMethodProperty$](|target|, {{@@asyncIterator}}, |F|).
1236012404
</div>
1236112405

12406+
<div algorithm>
12407+
To <dfn lt="converting arguments for an asynchronous iterator method">convert arguments for an asynchronous iterator method</dfn>,
12408+
given an [=interface=] |definition| that has an [=asynchronously iterable declaration=] and a
12409+
[=list=] of ECMAScript values |args|:
12410+
12411+
1. Let |idlArgs| be an empty list.
12412+
1. Let |argCount| be the number of arguments of |definition|'s
12413+
[=asynchronously iterable declaration=], or 0 if the [=asynchronously iterable declaration=]
12414+
does not have an argument list.
12415+
1. Let |i| be 0.
12416+
1. While |i| &lt; |argCount|:
12417+
1. If |i| ≥ |args|'s [=list/size=], or if |args|[|i|] is <emu-val>undefined</emu-val>,
12418+
then:
12419+
1. If the argument to the [=asynchronously iterable declaration=] at index |i| is
12420+
declared with a [=optional argument/default value=], then [=list/append=] that
12421+
default value to |idlArgs|.
12422+
1. Otherwise, [=list/append=] to |idlArgs| the special value "missing".
12423+
1. Otherwise, [=list/append=] to |idlArgs| the result of
12424+
[=converted to an IDL value|converting=] |args|[|i|] to the IDL type given in the
12425+
[=asynchronously iterable declaration=]'s argument list at index |i|.
12426+
1. Set |i| to |i| + 1.
12427+
1. Return |idlArgs|.
12428+
12429+
<p class="note">This is essentially a hyper-specialization of the
12430+
[=overload resolution algorithm=] for the case where no overloads are allowed and all arguments
12431+
are optional.</p>
12432+
</div>
1236212433

1236312434
<h5 id="es-default-asynchronous-iterator-object">Default asynchronous iterator objects</h5>
1236412435

@@ -12444,8 +12515,14 @@ The \[[Prototype]] [=internal slot=] of an [=asynchronous iterator prototype obj
1244412515
1. Set |object|'s [=default asynchronous iterator object/is finished=] to true.
1244512516
1. Return [=!=] [$CreateIterResultObject$](<emu-val>undefined</emu-val>,
1244612517
<emu-val>true</emu-val>).
12447-
1. Otherwise:
12518+
1. Otherwise, if |interface| has a [=pair asynchronously iterable declaration=]:
12519+
1. Assert: |next| is a [=value pair=].
1244812520
1. Return the [=iterator result=] for |next| and |kind|.
12521+
1. Otherwise:
12522+
1. Assert: |interface| has a [=value asynchronously iterable declaration=].
12523+
1. Assert: |next| is a value of the type that appears in the declaration.
12524+
1. Let |value| be |next|, [=converted to an ECMAScript value=].
12525+
1. Return [=!=] [$CreateIterResultObject$](|value|, <emu-val>false</emu-val>).
1244912526
1. Let |onFulfilled| be [=!=] [$CreateBuiltinFunction$](|fulfillSteps|, « »).
1245012527
1. Perform [=!=] [$PerformPromiseThen$](|nextPromise|, |onFulfilled|,
1245112528
<emu-val>undefined</emu-val>, |nextPromiseCapability|).

0 commit comments

Comments
 (0)