'use strict' const NOOP_RECURSOR = { size: 0, next () { return null } } exports.NOOP_RECURSOR = NOOP_RECURSOR function fork (recursor) { const buffer = [] return { shared () { const next = recursor() if (next !== null) buffer.push(next) return next }, recursor () { if (buffer.length > 0) return buffer.shift() return recursor() } } } exports.fork = fork function map (recursor, mapFn) { return () => { const next = recursor() if (next === null) return null return mapFn(next) } } exports.map = map function replay (state, create) { if (!state) { const recursor = create() if (recursor === NOOP_RECURSOR) { state = recursor } else { state = Object.assign({ buffer: [], done: false }, recursor) } } if (state === NOOP_RECURSOR) return {state, recursor: state} let done = false let index = 0 const next = () => { if (done) return null let retval = state.buffer[index] if (retval === undefined) { retval = state.buffer[index] = state.next() } index++ if (retval === null) { done = true } return retval } return {state, recursor: {next, size: state.size}} } exports.replay = replay function sequence (first, second) { let fromFirst = true return () => { if (fromFirst) { const next = first() if (next !== null) return next fromFirst = false } return second() } } exports.sequence = sequence function singleValue (value) { let done = false return () => { if (done) return null done = true return value } } exports.singleValue = singleValue function unshift (recursor, value) { return () => { if (value !== null) { const next = value value = null return next } return recursor() } } exports.unshift = unshift