Skip to content

Add make and convenience functions for async iterators #243

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

Merged
merged 3 commits into from
Aug 29, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Next version

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

## 1.5.2

Expand Down
27 changes: 27 additions & 0 deletions src/Core__AsyncIterator.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
// Generated by ReScript, PLEASE EDIT WITH CARE

import * as Caml_option from "rescript/lib/es6/caml_option.js";

function value(v) {
return {
done: false,
value: Caml_option.some(v)
};
}

function done(finalValue) {
return {
done: true,
value: finalValue
};
}

async function forEach(iterator, f) {
var iteratorDone = false;
Expand All @@ -10,7 +25,19 @@ async function forEach(iterator, f) {
};
}

var make = (function makeAsyncIterator(next) {
return {
next,
[Symbol.asyncIterator]() {
return this;
}
}
});

export {
make ,
value ,
done ,
forEach ,
}
/* No side effect */
19 changes: 19 additions & 0 deletions src/Core__AsyncIterator.res
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ type value<'a> = {
value: option<'a>,
}

let value = v => {
done: false,
value: Some(v),
}

let done = (~finalValue=?) => {
done: true,
value: finalValue,
}

@send external next: t<'a> => promise<value<'a>> = "next"

let forEach = async (iterator, f) => {
Expand All @@ -16,3 +26,12 @@ let forEach = async (iterator, f) => {
iteratorDone := done
}
}

let make: (unit => promise<value<'value>>) => t<'value> = %raw(`function makeAsyncIterator(next) {
return {
next,
[Symbol.asyncIterator]() {
return this;
}
}
}`)
82 changes: 81 additions & 1 deletion src/Core__AsyncIterator.resi
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,86 @@ type value<'a> = {
value: option<'a>,
}

/**
`make(nextFn)`

Creates an async iterator from a function that returns the next value of the iterator.

## Examples
- A simple example, creating an async iterator that returns 1, 2, 3:
```rescript
let context = ref(0)

let asyncIterator = AsyncIterator.make(async () => {
let currentValue = context.contents
// Increment current value
context := currentValue + 1

{
AsyncIterator.value: Some(currentValue),
done: currentValue >= 3
}
})

// This will log 1, 2, 3
await asyncIterator->AsyncIterator.forEach(value =>
switch value {
| Some(value) => Console.log(value)
| None => ()
}
)
```
*/
let make: (unit => promise<value<'value>>) => t<'value>

/**
`value(value)`

Shorthand for creating a value object with the provided value, and the `done` property set to false.

## Examples
```rescript
let context = ref(0)

let asyncIterator = AsyncIterator.make(async () => {
let currentValue = context.contents
// Increment current value
context := currentValue + 1

if currentValue >= 3 {
AsyncIterator.done()
} else {
AsyncIterator.value(currentValue)
}
})
```
*/
let value: 'value => value<'value>

/**
`done(~finalValue=?)`

Shorthand for creating a value object with the `done` property set to true, and the provided value as the final value, if any.

## Examples
```rescript
let context = ref(0)

let asyncIterator = AsyncIterator.make(async () => {
let currentValue = context.contents
// Increment current value
context := currentValue + 1

if currentValue >= 3 {
AsyncIterator.done()
} else {
AsyncIterator.value(currentValue)
}
})
```
*/
let done: (~finalValue: 'value=?) => value<'value>

/**
`next(asyncIterator)`

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

- Complete example, including looping over all values:
Expand Down
38 changes: 37 additions & 1 deletion test/IteratorTests.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,47 @@ Test.run([
"Async forEach"
], asyncResult.contents, eq, "second");

var asyncResult$1 = {
contents: undefined
};

var count = {
contents: 0
};

var asyncIterator$1 = Core__AsyncIterator.make(async function () {
var currentCount = count.contents;
count.contents = currentCount + 1 | 0;
if (currentCount === 3) {
return Core__AsyncIterator.done(currentCount);
} else {
return Core__AsyncIterator.value(currentCount);
}
});

await Core__AsyncIterator.forEach(asyncIterator$1, (function (v) {
if (v === 3) {
asyncResult$1.contents = "done";
} else {
console.log("next..");
}
}));

Test.run([
[
"IteratorTests.res",
69,
20,
54
],
"Creating your own async iterator"
], asyncResult$1.contents, eq, "done");

export {
eq ,
iterator ,
syncResult ,
asyncIterator ,
asyncResult ,
asyncIterator$1 as asyncIterator,
}
/* iterator Not a pure module */
25 changes: 25 additions & 0 deletions test/IteratorTests.res
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,28 @@ await asyncIterator->AsyncIterator.forEach(v => {
})

Test.run(__POS_OF__("Async forEach"), asyncResult.contents, eq, Some("second"))

%%private(
let asyncResult = ref(None)
let count = ref(0)
)

let asyncIterator = AsyncIterator.make(async () => {
let currentCount = count.contents
count := currentCount + 1

if currentCount === 3 {
AsyncIterator.done(~finalValue=currentCount)
} else {
AsyncIterator.value(currentCount)
}
})

await asyncIterator->AsyncIterator.forEach(v => {
switch v {
| Some(3) => asyncResult.contents = Some("done")
| _ => Console.log("next..")
}
})

Test.run(__POS_OF__("Creating your own async iterator"), asyncResult.contents, eq, Some("done"))
6 changes: 3 additions & 3 deletions test/TestSuite.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ var iterator = IteratorTests.iterator;

var syncResult = IteratorTests.syncResult;

var asyncIterator = IteratorTests.asyncIterator;

var asyncResult = IteratorTests.asyncResult;

var asyncIterator = IteratorTests.asyncIterator;

export {
bign ,
TestError ,
Expand Down Expand Up @@ -115,7 +115,7 @@ export {
eq ,
iterator ,
syncResult ,
asyncIterator ,
asyncResult ,
asyncIterator ,
}
/* IntTests Not a pure module */
Loading