scontainers
Version:
A container/collection/iterator library for JavaScript, comfortable to use, performant and versatile.
172 lines (131 loc) • 3.41 kB
JavaScript
;
function _implSymbol(target, sym, value) {
Object.defineProperty(target, sym, {
value,
configurable: true
});
return target[sym];
}
function _getSymbol(targetSymName, ...traitSets) {
let symbol;
traitSets.forEach(traitSet => {
const sym = traitSet[targetSymName];
if (typeof sym === 'symbol') {
if (!!symbol && symbol !== sym) {
throw new Error(`Symbol ${targetSymName} offered by multiple trait sets.`);
}
symbol = sym;
}
});
if (!symbol) {
throw new Error(`No trait set is providing symbol ${targetSymName}.`);
}
return symbol;
}
function _testTraitSet(traitSet) {
if (!traitSet || typeof traitSet === 'boolean' || typeof traitSet === 'number' || typeof traitSet === 'string') {
throw new Error(`${traitSet} cannot be used as a trait set.`);
}
}
const {
assert,
KVN
} = require('./utils_light.js');
const utilsTraits = require('./traits/utils.js');
_testTraitSet(utilsTraits);
const _toString = _getSymbol("toString", utilsTraits);
class ReorderedIterator {
constructor() {
this.state = ReorderedIterator.state.ready;
this.onNextFn = () => {};
this.onEndFn = () => {};
} // public interface
proceed() {
assert(this.state === ReorderedIterator.state.ready, `proceed() should be called only once.`);
this.state = ReorderedIterator.state.proceeding;
}
resume() {
assert(this.state === ReorderedIterator.state.proceeding, `resume() should be called only when the ReorderedIterator is already proceeding and not stopped.`);
}
stop() {
assert(this.state === ReorderedIterator.state.proceeding, `stop() should be called only when the ReorderedIterator is proceeding and not yet stopped.`);
this.state = ReorderedIterator.state.stopped;
} // register handlers for some common events...
onNext(fn) {
this.onNextFn = fn;
return this;
}
onEnd(fn) {
this.onEndFn = fn;
return this;
} // sends the events above
_pushNext(kvn) {
if (!kvn) {
return;
}
assert(kvn instanceof KVN, `Received a ${kvn}`);
this.onNextFn(kvn);
}
_pushEnd() {
this.onEndFn();
}
toString() {
return `${this.constructor.name}{state:${this.state[_toString]()}}`;
}
}
ReorderedIterator.state = {
ready: Symbol(`ready`),
proceeding: Symbol(`proceeding`),
stopped: Symbol(`stopped`)
};
ReorderedIterator.MapReorderedIterator = class extends ReorderedIterator {
constructor(rit, mapFn) {
super();
this.rit = rit;
this.mapFn = mapFn;
this.rit.onNext(kvn => this._pushNext(this.mapFn(kvn))).onEnd(this._pushEnd.bind(this));
}
proceed() {
super.proceed();
this.rit.proceed();
}
resume() {
super.resume();
this.rit.resume();
}
stop() {
super.stop();
this.rit.stop();
}
};
ReorderedIterator.FromIterator = class extends ReorderedIterator {
constructor(it) {
super();
this.it = it;
this.state = ReorderedIterator.state.ready;
this.next = this.it.next();
}
proceed() {
super.proceed();
this._work();
}
resume() {
super.resume();
this._work();
}
stop() {
super.stop();
this.next = undefined;
}
_work() {
while (this.next) {
const next = this.next;
this.next = this.it.next();
this._pushNext(next);
}
this._pushEnd();
}
};
module.exports = {
ReorderedIterator
};