Skip to content

Commit e3abc35

Browse files
authored
Merge pull request #1 from projectfluent/async-iterable-sync-iterator
Add [Symbol.iterator] to CachedAsyncIterable
2 parents 1ba84c6 + fd48e98 commit e3abc35

4 files changed

+135
-0
lines changed

src/cached_async_iterable.mjs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,34 @@ export default class CachedAsyncIterable {
2323
this.seen = [];
2424
}
2525

26+
/**
27+
* Synchronous iterator over the cached elements.
28+
*
29+
* Return a generator object implementing the iterator protocol over the
30+
* cached elements of the original (async or sync) iterable.
31+
*/
32+
[Symbol.iterator]() {
33+
const {seen} = this;
34+
let cur = 0;
35+
36+
return {
37+
next() {
38+
if (seen.length === cur) {
39+
return {value: undefined, done: true};
40+
}
41+
return seen[cur++];
42+
}
43+
};
44+
}
45+
46+
/**
47+
* Asynchronous iterator caching the yielded elements.
48+
*
49+
* Elements yielded by the original iterable will be cached and available
50+
* synchronously. Returns an async generator object implementing the
51+
* iterator protocol over the elements of the original (async or sync)
52+
* iterable.
53+
*/
2654
[Symbol.asyncIterator]() {
2755
const { seen, iterator } = this;
2856
let cur = 0;
@@ -51,5 +79,8 @@ export default class CachedAsyncIterable {
5179
seen.push(await iterator.next());
5280
}
5381
}
82+
// Return the last cached {value, done} object to allow the calling
83+
// code to decide if it needs to call touchNext again.
84+
return seen[seen.length - 1];
5485
}
5586
}

src/cached_sync_iterable.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,8 @@ export default class CachedSyncIterable {
4949
seen.push(iterator.next());
5050
}
5151
}
52+
// Return the last cached {value, done} object to allow the calling
53+
// code to decide if it needs to call touchNext again.
54+
return seen[seen.length - 1];
5255
}
5356
}

test/cached_async_iterable_test.js

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,75 @@ suite("CachedAsyncIterable", function() {
5555
});
5656
});
5757

58+
suite("sync iteration over cached elements", function(){
59+
let o1, o2;
60+
61+
suiteSetup(function() {
62+
o1 = Object();
63+
o2 = Object();
64+
});
65+
66+
test("sync iterable with no cached elements yet", function() {
67+
function *generate() {
68+
yield *[o1, o2];
69+
}
70+
71+
const iterable = new CachedAsyncIterable(generate());
72+
assert.deepEqual([...iterable], []);
73+
});
74+
75+
test("sync iterable with a few elements cached so far", async function() {
76+
function *generate() {
77+
yield *[o1, o2];
78+
}
79+
80+
const iterable = new CachedAsyncIterable(generate());
81+
await iterable.touchNext();
82+
assert.deepEqual([...iterable], [o1]);
83+
});
84+
85+
test("iterable with all cached elements", async function() {
86+
function *generate() {
87+
yield *[o1, o2];
88+
}
89+
90+
const iterable = new CachedAsyncIterable(generate());
91+
await iterable.touchNext();
92+
await iterable.touchNext();
93+
assert.deepEqual([...iterable], [o1, o2]);
94+
});
95+
96+
test("async iterable with no cached elements yet", async function() {
97+
async function *generate() {
98+
yield *[o1, o2];
99+
}
100+
101+
const iterable = new CachedAsyncIterable(generate());
102+
assert.deepEqual([...iterable], []);
103+
});
104+
105+
test("async iterable with a few elements cached so far", async function() {
106+
async function *generate() {
107+
yield *[o1, o2];
108+
}
109+
110+
const iterable = new CachedAsyncIterable(generate());
111+
await iterable.touchNext();
112+
assert.deepEqual([...iterable], [o1]);
113+
});
114+
115+
test("async iterable with all cached elements", async function() {
116+
async function *generate() {
117+
yield *[o1, o2];
118+
}
119+
120+
const iterable = new CachedAsyncIterable(generate());
121+
await iterable.touchNext();
122+
await iterable.touchNext();
123+
assert.deepEqual([...iterable], [o1, o2]);
124+
});
125+
});
126+
58127
suite("async iteration", function(){
59128
let o1, o2;
60129

@@ -172,5 +241,21 @@ suite("CachedAsyncIterable", function() {
172241
}
173242
assert.deepEqual(values, [o1, o2]);
174243
});
244+
245+
test("returns the most recent {value, done} object", async function() {
246+
const iterable = new CachedAsyncIterable([o1, o2]);
247+
assert.deepEqual(
248+
await iterable.touchNext(),
249+
{value: o1, done: false});
250+
assert.deepEqual(
251+
await iterable.touchNext(),
252+
{value: o2, done: false});
253+
assert.deepEqual(
254+
await iterable.touchNext(),
255+
{value: undefined, done: true});
256+
assert.deepEqual(
257+
await iterable.touchNext(),
258+
{value: undefined, done: true});
259+
});
175260
});
176261
});

test/cached_sync_iterable_test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,5 +137,21 @@ suite("CachedSyncIterable", function() {
137137
iterable.touchNext();
138138
assert.deepEqual([...iterable], [o1, o2]);
139139
});
140+
141+
test("returns the most recent {value, done} object", function() {
142+
const iterable = new CachedSyncIterable([o1, o2]);
143+
assert.deepEqual(
144+
iterable.touchNext(),
145+
{value: o1, done: false});
146+
assert.deepEqual(
147+
iterable.touchNext(),
148+
{value: o2, done: false});
149+
assert.deepEqual(
150+
iterable.touchNext(),
151+
{value: undefined, done: true});
152+
assert.deepEqual(
153+
iterable.touchNext(),
154+
{value: undefined, done: true});
155+
});
140156
});
141157
});

0 commit comments

Comments
 (0)