blob: c35f6957433c72b96714608724a75156e20b0b55 [file] [log] [blame]
Leo Repp58b9f112021-11-22 11:57:47 +01001'use strict';
2const from = require('from2');
3const pIsPromise = require('p-is-promise');
4
5module.exports = x => {
6 if (Array.isArray(x)) {
7 x = x.slice();
8 }
9
10 let promise;
11 let iterator;
12
13 prepare(x);
14
15 function prepare(value) {
16 x = value;
17 promise = pIsPromise(x) ? x : null;
18 // we don't iterate on strings and buffers since slicing them is ~7x faster
19 const shouldIterate = !promise && x[Symbol.iterator] && typeof x !== 'string' && !Buffer.isBuffer(x);
20 iterator = shouldIterate ? x[Symbol.iterator]() : null;
21 }
22
23 return from(function reader(size, cb) {
24 if (promise) {
25 promise.then(prepare).then(() => reader.call(this, size, cb), cb);
26 return;
27 }
28
29 if (iterator) {
30 const obj = iterator.next();
31 setImmediate(cb, null, obj.done ? null : obj.value);
32 return;
33 }
34
35 if (x.length === 0) {
36 setImmediate(cb, null, null);
37 return;
38 }
39
40 const chunk = x.slice(0, size);
41 x = x.slice(size);
42
43 setImmediate(cb, null, chunk);
44 });
45};
46
47module.exports.obj = x => {
48 if (Array.isArray(x)) {
49 x = x.slice();
50 }
51
52 let promise;
53 let iterator;
54
55 prepare(x);
56
57 function prepare(value) {
58 x = value;
59 promise = pIsPromise(x) ? x : null;
60 iterator = !promise && x[Symbol.iterator] ? x[Symbol.iterator]() : null;
61 }
62
63 return from.obj(function reader(size, cb) {
64 if (promise) {
65 promise.then(prepare).then(() => reader.call(this, size, cb), cb);
66 return;
67 }
68
69 if (iterator) {
70 const obj = iterator.next();
71 setImmediate(cb, null, obj.done ? null : obj.value);
72 return;
73 }
74
75 this.push(x);
76
77 setImmediate(cb, null, null);
78 });
79};