Skip to content

Add [Symbol.iterator] to CachedAsyncIterable #1

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 2 commits into from
Jun 8, 2018
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
31 changes: 31 additions & 0 deletions src/cached_async_iterable.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,34 @@ export default class CachedAsyncIterable {
this.seen = [];
}

/**
* Synchronous iterator over the cached elements.
*
* Return a generator object implementing the iterator protocol over the
* cached elements of the original (async or sync) iterable.
*/
[Symbol.iterator]() {
const {seen} = this;
let cur = 0;

return {
next() {
if (seen.length === cur) {
return {value: undefined, done: true};
}
return seen[cur++];
}
};
}

/**
* Asynchronous iterator caching the yielded elements.
*
* Elements yielded by the original iterable will be cached and available
* synchronously. Returns an async generator object implementing the
* iterator protocol over the elements of the original (async or sync)
* iterable.
*/
[Symbol.asyncIterator]() {
const { seen, iterator } = this;
let cur = 0;
Expand Down Expand Up @@ -51,5 +79,8 @@ export default class CachedAsyncIterable {
seen.push(await iterator.next());
}
}
// Return the last cached {value, done} object to allow the calling
// code to decide if it needs to call touchNext again.
return seen[seen.length - 1];
}
}
3 changes: 3 additions & 0 deletions src/cached_sync_iterable.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,8 @@ export default class CachedSyncIterable {
seen.push(iterator.next());
}
}
// Return the last cached {value, done} object to allow the calling
// code to decide if it needs to call touchNext again.
return seen[seen.length - 1];
}
}
85 changes: 85 additions & 0 deletions test/cached_async_iterable_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,75 @@ suite("CachedAsyncIterable", function() {
});
});

suite("sync iteration over cached elements", function(){
let o1, o2;

suiteSetup(function() {
o1 = Object();
o2 = Object();
});

test("sync iterable with no cached elements yet", function() {
function *generate() {
yield *[o1, o2];
}

const iterable = new CachedAsyncIterable(generate());
assert.deepEqual([...iterable], []);
});

test("sync iterable with a few elements cached so far", async function() {
function *generate() {
yield *[o1, o2];
}

const iterable = new CachedAsyncIterable(generate());
await iterable.touchNext();
assert.deepEqual([...iterable], [o1]);
});

test("iterable with all cached elements", async function() {
function *generate() {
yield *[o1, o2];
}

const iterable = new CachedAsyncIterable(generate());
await iterable.touchNext();
await iterable.touchNext();
assert.deepEqual([...iterable], [o1, o2]);
});

test("async iterable with no cached elements yet", async function() {
async function *generate() {
yield *[o1, o2];
}

const iterable = new CachedAsyncIterable(generate());
assert.deepEqual([...iterable], []);
});

test("async iterable with a few elements cached so far", async function() {
async function *generate() {
yield *[o1, o2];
}

const iterable = new CachedAsyncIterable(generate());
await iterable.touchNext();
assert.deepEqual([...iterable], [o1]);
});

test("async iterable with all cached elements", async function() {
async function *generate() {
yield *[o1, o2];
}

const iterable = new CachedAsyncIterable(generate());
await iterable.touchNext();
await iterable.touchNext();
assert.deepEqual([...iterable], [o1, o2]);
});
});

suite("async iteration", function(){
let o1, o2;

Expand Down Expand Up @@ -172,5 +241,21 @@ suite("CachedAsyncIterable", function() {
}
assert.deepEqual(values, [o1, o2]);
});

test("returns the most recent {value, done} object", async function() {
const iterable = new CachedAsyncIterable([o1, o2]);
assert.deepEqual(
await iterable.touchNext(),
{value: o1, done: false});
assert.deepEqual(
await iterable.touchNext(),
{value: o2, done: false});
assert.deepEqual(
await iterable.touchNext(),
{value: undefined, done: true});
assert.deepEqual(
await iterable.touchNext(),
{value: undefined, done: true});
});
});
});
16 changes: 16 additions & 0 deletions test/cached_sync_iterable_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,21 @@ suite("CachedSyncIterable", function() {
iterable.touchNext();
assert.deepEqual([...iterable], [o1, o2]);
});

test("returns the most recent {value, done} object", function() {
const iterable = new CachedSyncIterable([o1, o2]);
assert.deepEqual(
iterable.touchNext(),
{value: o1, done: false});
assert.deepEqual(
iterable.touchNext(),
{value: o2, done: false});
assert.deepEqual(
iterable.touchNext(),
{value: undefined, done: true});
assert.deepEqual(
iterable.touchNext(),
{value: undefined, done: true});
});
});
});