Skip to content

Commit ddc4a08

Browse files
authored
Add make and convenience functions for async iterators (#243)
* add make and convenience functions for async iterators * changelog * fix doc examples
1 parent 22642ea commit ddc4a08

7 files changed

+193
-5
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Next version
44

55
- Optimize compare and equal functions. https://github.com/rescript-association/rescript-core/pull/238
6+
- Add `make` and `done` + `value` functions to `AsyncIterator`. https://github.com/rescript-association/rescript-core/pull/243
67

78
## 1.5.2
89

src/Core__AsyncIterator.mjs

+27
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
// Generated by ReScript, PLEASE EDIT WITH CARE
22

3+
import * as Caml_option from "rescript/lib/es6/caml_option.js";
4+
5+
function value(v) {
6+
return {
7+
done: false,
8+
value: Caml_option.some(v)
9+
};
10+
}
11+
12+
function done(finalValue) {
13+
return {
14+
done: true,
15+
value: finalValue
16+
};
17+
}
318

419
async function forEach(iterator, f) {
520
var iteratorDone = false;
@@ -10,7 +25,19 @@ async function forEach(iterator, f) {
1025
};
1126
}
1227

28+
var make = (function makeAsyncIterator(next) {
29+
return {
30+
next,
31+
[Symbol.asyncIterator]() {
32+
return this;
33+
}
34+
}
35+
});
36+
1337
export {
38+
make ,
39+
value ,
40+
done ,
1441
forEach ,
1542
}
1643
/* No side effect */

src/Core__AsyncIterator.res

+19
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ type value<'a> = {
55
value: option<'a>,
66
}
77

8+
let value = v => {
9+
done: false,
10+
value: Some(v),
11+
}
12+
13+
let done = (~finalValue=?) => {
14+
done: true,
15+
value: finalValue,
16+
}
17+
818
@send external next: t<'a> => promise<value<'a>> = "next"
919

1020
let forEach = async (iterator, f) => {
@@ -16,3 +26,12 @@ let forEach = async (iterator, f) => {
1626
iteratorDone := done
1727
}
1828
}
29+
30+
let make: (unit => promise<value<'value>>) => t<'value> = %raw(`function makeAsyncIterator(next) {
31+
return {
32+
next,
33+
[Symbol.asyncIterator]() {
34+
return this;
35+
}
36+
}
37+
}`)

src/Core__AsyncIterator.resi

+81-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,86 @@ type value<'a> = {
1919
value: option<'a>,
2020
}
2121

22+
/**
23+
`make(nextFn)`
24+
25+
Creates an async iterator from a function that returns the next value of the iterator.
26+
27+
## Examples
28+
- A simple example, creating an async iterator that returns 1, 2, 3:
29+
```rescript
30+
let context = ref(0)
31+
32+
let asyncIterator = AsyncIterator.make(async () => {
33+
let currentValue = context.contents
34+
// Increment current value
35+
context := currentValue + 1
36+
37+
{
38+
AsyncIterator.value: Some(currentValue),
39+
done: currentValue >= 3
40+
}
41+
})
42+
43+
// This will log 1, 2, 3
44+
await asyncIterator->AsyncIterator.forEach(value =>
45+
switch value {
46+
| Some(value) => Console.log(value)
47+
| None => ()
48+
}
49+
)
50+
```
51+
*/
52+
let make: (unit => promise<value<'value>>) => t<'value>
53+
54+
/**
55+
`value(value)`
56+
57+
Shorthand for creating a value object with the provided value, and the `done` property set to false.
58+
59+
## Examples
60+
```rescript
61+
let context = ref(0)
62+
63+
let asyncIterator = AsyncIterator.make(async () => {
64+
let currentValue = context.contents
65+
// Increment current value
66+
context := currentValue + 1
67+
68+
if currentValue >= 3 {
69+
AsyncIterator.done()
70+
} else {
71+
AsyncIterator.value(currentValue)
72+
}
73+
})
74+
```
75+
*/
76+
let value: 'value => value<'value>
77+
78+
/**
79+
`done(~finalValue=?)`
80+
81+
Shorthand for creating a value object with the `done` property set to true, and the provided value as the final value, if any.
82+
83+
## Examples
84+
```rescript
85+
let context = ref(0)
86+
87+
let asyncIterator = AsyncIterator.make(async () => {
88+
let currentValue = context.contents
89+
// Increment current value
90+
context := currentValue + 1
91+
92+
if currentValue >= 3 {
93+
AsyncIterator.done()
94+
} else {
95+
AsyncIterator.value(currentValue)
96+
}
97+
})
98+
```
99+
*/
100+
let done: (~finalValue: 'value=?) => value<'value>
101+
22102
/**
23103
`next(asyncIterator)`
24104

@@ -30,7 +110,7 @@ See [async iterator protocols](https://developer.mozilla.org/en-US/docs/Web/Java
30110
- A simple example, getting the next value:
31111
```rescript
32112
@val external asyncIterator: AsyncIterator.t<int> = "someAsyncIterator"
33-
let {AsyncIterator.done, value} = await asyncIterator->AsyncIterator.next
113+
let value = await asyncIterator->AsyncIterator.next
34114
```
35115

36116
- Complete example, including looping over all values:

test/IteratorTests.mjs

+37-1
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,47 @@ Test.run([
6767
"Async forEach"
6868
], asyncResult.contents, eq, "second");
6969

70+
var asyncResult$1 = {
71+
contents: undefined
72+
};
73+
74+
var count = {
75+
contents: 0
76+
};
77+
78+
var asyncIterator$1 = Core__AsyncIterator.make(async function () {
79+
var currentCount = count.contents;
80+
count.contents = currentCount + 1 | 0;
81+
if (currentCount === 3) {
82+
return Core__AsyncIterator.done(currentCount);
83+
} else {
84+
return Core__AsyncIterator.value(currentCount);
85+
}
86+
});
87+
88+
await Core__AsyncIterator.forEach(asyncIterator$1, (function (v) {
89+
if (v === 3) {
90+
asyncResult$1.contents = "done";
91+
} else {
92+
console.log("next..");
93+
}
94+
}));
95+
96+
Test.run([
97+
[
98+
"IteratorTests.res",
99+
69,
100+
20,
101+
54
102+
],
103+
"Creating your own async iterator"
104+
], asyncResult$1.contents, eq, "done");
105+
70106
export {
71107
eq ,
72108
iterator ,
73109
syncResult ,
74-
asyncIterator ,
75110
asyncResult ,
111+
asyncIterator$1 as asyncIterator,
76112
}
77113
/* iterator Not a pure module */

test/IteratorTests.res

+25
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,28 @@ await asyncIterator->AsyncIterator.forEach(v => {
4242
})
4343

4444
Test.run(__POS_OF__("Async forEach"), asyncResult.contents, eq, Some("second"))
45+
46+
%%private(
47+
let asyncResult = ref(None)
48+
let count = ref(0)
49+
)
50+
51+
let asyncIterator = AsyncIterator.make(async () => {
52+
let currentCount = count.contents
53+
count := currentCount + 1
54+
55+
if currentCount === 3 {
56+
AsyncIterator.done(~finalValue=currentCount)
57+
} else {
58+
AsyncIterator.value(currentCount)
59+
}
60+
})
61+
62+
await asyncIterator->AsyncIterator.forEach(v => {
63+
switch v {
64+
| Some(3) => asyncResult.contents = Some("done")
65+
| _ => Console.log("next..")
66+
}
67+
})
68+
69+
Test.run(__POS_OF__("Creating your own async iterator"), asyncResult.contents, eq, Some("done"))

test/TestSuite.mjs

+3-3
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,10 @@ var iterator = IteratorTests.iterator;
7878

7979
var syncResult = IteratorTests.syncResult;
8080

81-
var asyncIterator = IteratorTests.asyncIterator;
82-
8381
var asyncResult = IteratorTests.asyncResult;
8482

83+
var asyncIterator = IteratorTests.asyncIterator;
84+
8585
export {
8686
bign ,
8787
TestError ,
@@ -115,7 +115,7 @@ export {
115115
eq ,
116116
iterator ,
117117
syncResult ,
118-
asyncIterator ,
119118
asyncResult ,
119+
asyncIterator ,
120120
}
121121
/* IntTests Not a pure module */

0 commit comments

Comments
 (0)