Skip to content

Commit 17a5d5f

Browse files
authored
Add iterator and asyncIterator forEach helpers (#175)
* add iterator and asyncIterator forEach helpers * changelog + fix docstrings * fix docstring errors
1 parent e9863e5 commit 17a5d5f

13 files changed

+249
-18
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- Remove internal xxxU helper functions that are not needed anymore in uncurried mode. https://github.com/rescript-association/rescript-core/pull/191
99
- Rename `Object.empty` to `Object.make` for consistency.
1010
- Add dynamic `import`. https://github.com/rescript-association/rescript-core/pull/178
11+
- Add `Iterator.forEach` and `AsyncIterator.forEach` helpers for iterators. https://github.com/rescript-association/rescript-core/pull/175
1112

1213
## 1.0.0
1314

src/Core__AsyncIterator.mjs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,16 @@
11
// Generated by ReScript, PLEASE EDIT WITH CARE
2-
/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
2+
3+
4+
async function forEach(iterator, f) {
5+
var iteratorDone = false;
6+
while(!iteratorDone) {
7+
var match = await iterator.next();
8+
f(match.value);
9+
iteratorDone = match.done;
10+
};
11+
}
12+
13+
export {
14+
forEach ,
15+
}
16+
/* No side effect */

src/Core__AsyncIterator.res

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,13 @@ type value<'a> = {
66
}
77

88
@send external next: t<'a> => promise<value<'a>> = "next"
9+
10+
let forEach = async (iterator, f) => {
11+
let iteratorDone = ref(false)
12+
13+
while !iteratorDone.contents {
14+
let {done, value} = await iterator->next
15+
f(value)
16+
iteratorDone := done
17+
}
18+
}

src/Core__AsyncIterator.resi

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,23 @@ let processMyAsyncIterator = async () => {
5858
*/
5959
@send
6060
external next: t<'a> => promise<value<'a>> = "next"
61+
62+
/**
63+
`forEach(iterator, fn)` consumes all values in the async iterator and runs the callback `fn` for each value.
64+
65+
See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN.
66+
67+
## Examples
68+
```rescript
69+
// Let's pretend we get an async iterator returning ints from somewhere.
70+
@val external asyncIterator: AsyncIterator.t<int> = "someAsyncIterator"
71+
72+
await asyncIterator->AsyncIterator.forEach(value =>
73+
switch value {
74+
| Some(value) if value > 10 => Console.log("More than 10!")
75+
| _ => ()
76+
}
77+
)
78+
```
79+
*/
80+
let forEach: (t<'a>, option<'a> => unit) => promise<unit>

src/Core__Iterator.mjs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,16 @@
11
// Generated by ReScript, PLEASE EDIT WITH CARE
2-
/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
2+
3+
4+
function forEach(iterator, f) {
5+
var iteratorDone = false;
6+
while(!iteratorDone) {
7+
var match = iterator.next();
8+
f(match.value);
9+
iteratorDone = match.done;
10+
};
11+
}
12+
13+
export {
14+
forEach ,
15+
}
16+
/* No side effect */

src/Core__Iterator.res

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,13 @@ type value<'a> = {
88
@send external next: t<'a> => value<'a> = "next"
99
external toArray: t<'a> => array<'a> = "Array.from"
1010
external toArrayWithMapper: (t<'a>, 'a => 'b) => array<'b> = "Array.from"
11+
12+
let forEach = (iterator, f) => {
13+
let iteratorDone = ref(false)
14+
15+
while !iteratorDone.contents {
16+
let {done, value} = iterator->next
17+
f(value)
18+
iteratorDone := done
19+
}
20+
}

src/Core__Iterator.resi

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript
3131
## Examples
3232
```rescript
3333
@val external someIterator: Iterator.t<int> = "someIterator"
34+
3435
// Pulls out the next value of the iterator
3536
let {Iterator.done, value} = someIterator->Iterator.next
3637
```
@@ -79,3 +80,22 @@ Console.log(mapKeysAsArray) // Logs [7, 8] to the console.
7980
```
8081
*/
8182
external toArrayWithMapper: (t<'a>, 'a => 'b) => array<'b> = "Array.from"
83+
84+
/**
85+
`forEach(iterator, fn)` consumes all values in the iterator and runs the callback `fn` for each value.
86+
87+
See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN.
88+
89+
## Examples
90+
```rescript
91+
@val external someIterator: Iterator.t<int> = "someIterator"
92+
93+
someIterator->Iterator.forEach(value =>
94+
switch value {
95+
| Some(value) if value > 10 => Console.log("More than 10!")
96+
| _ => ()
97+
}
98+
)
99+
```
100+
*/
101+
let forEach: (t<'a>, option<'a> => unit) => unit

src/Core__List.resi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,9 @@ with `f`. Returns an empty list if `length` is negative.
185185
## Examples
186186
187187
```rescript
188-
List.fromInitializer(5, i => i) // list{0, 1, 2, 3, 4}
188+
List.fromInitializer(~length=5, i => i) // list{0, 1, 2, 3, 4}
189189
190-
List.fromInitializer(5, i => i * i) // list{0, 1, 4, 9, 16}
190+
List.fromInitializer(~length=5, i => i * i) // list{0, 1, 4, 9, 16}
191191
```
192192
*/
193193
let fromInitializer: (~length: int, int => 'a) => t<'a>

src/RescriptCore.res

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,31 +59,36 @@ value.
5959
6060
## Examples
6161
62-
`MathUtils.res` file:
62+
`Core__Array.res` file:
6363
6464
```rescript
65-
let add = (a, b) => a + b
66-
let sub = (a, b) => a - b
65+
@send external indexOf: (array<'a>, 'a) => int = "indexOf"
66+
67+
let indexOfOpt = (arr, item) =>
68+
switch arr->indexOf(item) {
69+
| -1 => None
70+
| index => Some(index)
71+
}
6772
```
68-
In other file you can import the `add` value defined in `MathUtils.res`
73+
In other file you can import the `indexOfOpt` value defined in `Core__Array.res`
6974
7075
```rescript
7176
let main = async () => {
72-
let add = await import(MathUtils.add)
73-
let onePlusOne = add(1, 1)
74-
Console.log(onePlusOne)
77+
let indexOfOpt = await import(Core__Array.indexOfOpt)
78+
let index = indexOfOpt([1, 2], 2)
79+
Console.log(index)
7580
}
7681
```
7782
7883
Compiles to:
7984
8085
```javascript
8186
async function main() {
82-
var add = await import("./MathUtils.mjs").then(function(m) {
83-
return m.add;
87+
var add = await import("./Core__Array.mjs").then(function(m) {
88+
return m.indexOfOpt;
8489
});
85-
var onePlusOne = add(1, 1);
86-
console.log(onePlusOne);
90+
var index = indexOfOpt([1, 2], 2);
91+
console.log(index);
8792
}
8893
```
8994
*/

test/IteratorTests.mjs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Generated by ReScript, PLEASE EDIT WITH CARE
2+
3+
import * as Test from "./Test.mjs";
4+
import * as Caml_obj from "rescript/lib/es6/caml_obj.js";
5+
import * as Core__Iterator from "../src/Core__Iterator.mjs";
6+
import * as Core__AsyncIterator from "../src/Core__AsyncIterator.mjs";
7+
8+
var eq = Caml_obj.equal;
9+
10+
var iterator = ((() => {
11+
var array1 = ['a', 'b', 'c'];
12+
var iterator1 = array1[Symbol.iterator]();
13+
return iterator1
14+
})());
15+
16+
var syncResult = {
17+
contents: undefined
18+
};
19+
20+
Core__Iterator.forEach(iterator, (function (v) {
21+
if (v === "b") {
22+
syncResult.contents = "b";
23+
return ;
24+
}
25+
26+
}));
27+
28+
Test.run([
29+
[
30+
"IteratorTests.res",
31+
21,
32+
20,
33+
34
34+
],
35+
"Sync forEach"
36+
], syncResult.contents, eq, "b");
37+
38+
var asyncIterator = ((() => {
39+
var map1 = new Map();
40+
41+
map1.set('first', '1');
42+
map1.set('second', '2');
43+
44+
var iterator1 = map1[Symbol.iterator]();
45+
return iterator1;
46+
})());
47+
48+
var asyncResult = {
49+
contents: undefined
50+
};
51+
52+
await Core__AsyncIterator.forEach(asyncIterator, (function (v) {
53+
if (v !== undefined && v[0] === "second") {
54+
asyncResult.contents = "second";
55+
return ;
56+
}
57+
58+
}));
59+
60+
Test.run([
61+
[
62+
"IteratorTests.res",
63+
44,
64+
20,
65+
35
66+
],
67+
"Async forEach"
68+
], asyncResult.contents, eq, "second");
69+
70+
export {
71+
eq ,
72+
iterator ,
73+
syncResult ,
74+
asyncIterator ,
75+
asyncResult ,
76+
}
77+
/* iterator Not a pure module */

test/IteratorTests.res

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
open RescriptCore
2+
3+
let eq = (a, b) => a == b
4+
5+
let iterator: Iterator.t<string> = %raw(`
6+
(() => {
7+
var array1 = ['a', 'b', 'c'];
8+
var iterator1 = array1[Symbol.iterator]();
9+
return iterator1
10+
})()
11+
`)
12+
13+
let syncResult = ref(None)
14+
15+
iterator->Iterator.forEach(v => {
16+
if v === Some("b") {
17+
syncResult.contents = Some("b")
18+
}
19+
})
20+
21+
Test.run(__POS_OF__("Sync forEach"), syncResult.contents, eq, Some("b"))
22+
23+
let asyncIterator: AsyncIterator.t<(string, string)> = %raw(`
24+
(() => {
25+
var map1 = new Map();
26+
27+
map1.set('first', '1');
28+
map1.set('second', '2');
29+
30+
var iterator1 = map1[Symbol.iterator]();
31+
return iterator1;
32+
})()
33+
`)
34+
35+
let asyncResult = ref(None)
36+
37+
await asyncIterator->AsyncIterator.forEach(v => {
38+
switch v {
39+
| Some(("second", _value)) => asyncResult.contents = Some("second")
40+
| _ => ()
41+
}
42+
})
43+
44+
Test.run(__POS_OF__("Async forEach"), asyncResult.contents, eq, Some("second"))

test/TestSuite.mjs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Generated by ReScript, PLEASE EDIT WITH CARE
22

33
import * as IntTests from "./IntTests.mjs";
4+
import * as DictTests from "./DictTests.mjs";
45
import * as JsonTests from "./JsonTests.mjs";
56
import * as TestTests from "./TestTests.mjs";
67
import * as ArrayTests from "./ArrayTests.mjs";
@@ -9,6 +10,7 @@ import * as FloatTests from "./FloatTests.mjs";
910
import * as ObjectTests from "./ObjectTests.mjs";
1011
import * as PromiseTest from "./PromiseTest.mjs";
1112
import * as ResultTests from "./ResultTests.mjs";
13+
import * as IteratorTests from "./IteratorTests.mjs";
1214
import * as NullableTests from "./NullableTests.mjs";
1315
import * as TypedArrayTests from "./TypedArrayTests.mjs";
1416

@@ -66,12 +68,20 @@ var areSame = TypedArrayTests.areSame;
6668

6769
var o = TypedArrayTests.o;
6870

69-
var eq = FloatTests.eq;
70-
7171
var decodeJsonTest = JsonTests.decodeJsonTest;
7272

7373
var shouldHandleNullableValues = NullableTests.shouldHandleNullableValues;
7474

75+
var eq = IteratorTests.eq;
76+
77+
var iterator = IteratorTests.iterator;
78+
79+
var syncResult = IteratorTests.syncResult;
80+
81+
var asyncIterator = IteratorTests.asyncIterator;
82+
83+
var asyncResult = IteratorTests.asyncResult;
84+
7585
export {
7686
bign ,
7787
TestError ,
@@ -100,8 +110,12 @@ export {
100110
assertWillThrow ,
101111
areSame ,
102112
o ,
103-
eq ,
104113
decodeJsonTest ,
105114
shouldHandleNullableValues ,
115+
eq ,
116+
iterator ,
117+
syncResult ,
118+
asyncIterator ,
119+
asyncResult ,
106120
}
107121
/* IntTests Not a pure module */

test/TestSuite.res

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ include TypedArrayTests
99
include FloatTests
1010
include JsonTests
1111
include NullableTests
12+
include DictTests
13+
include IteratorTests

0 commit comments

Comments
 (0)