UNPKG

@effect-ts/system

Version:

Effect-TS is a zero dependency set of libraries to write highly productive, purely functional TypeScript at scale.

1,891 lines (1,544 loc) 52 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Schedule = void 0; exports.addDelay = addDelay; exports.addDelayM = addDelayM; exports.addDelayM_ = addDelayM_; exports.addDelay_ = addDelay_; exports.andThen = andThen; exports.andThenEither = andThenEither; exports.andThenEither_ = andThenEither_; exports.andThen_ = andThen_; exports.as = as; exports.bothInOut = bothInOut; exports.bothInOut_ = bothInOut_; exports.check = check; exports.checkM = checkM; exports.checkM_ = checkM_; exports.check_ = check_; exports.choose = choose; exports.chooseMerge = chooseMerge; exports.chooseMerge_ = chooseMerge_; exports.choose_ = choose_; exports.collectAll = collectAll; exports.collectAllIdentity = collectAllIdentity; exports.compose = compose; exports.compose_ = compose_; exports.contramap = contramap; exports.contramap_ = contramap_; exports.count = void 0; exports.delayed = delayed; exports.delayedFrom = delayedFrom; exports.delayedM = delayedM; exports.delayedM_ = delayedM_; exports.delayed_ = delayed_; exports.dimap = dimap; exports.dimap_ = dimap_; exports.driver = driver; exports.duration = duration; exports.durations = durations; exports.elapsed = void 0; exports.ensuring = ensuring; exports.ensuring_ = ensuring_; exports.exponential = exponential; exports.fibonacci = fibonacci; exports.first = first; exports.fixed = fixed; exports.fold = fold; exports.foldM = foldM; exports.foldM_ = foldM_; exports.fold_ = fold_; exports.forever = void 0; exports.fromFunction = fromFunction; exports.identity = identity; exports.intersectWith = intersectWith; exports.intersectWith_ = intersectWith_; exports.intersection = intersection; exports.intersection_ = intersection_; exports.jittered = jittered; exports.jittered_ = jittered_; exports.left = left; exports.linear = linear; exports.map = map; exports.mapM = mapM; exports.mapM_ = mapM_; exports.map_ = map_; exports.modifyDelay = modifyDelay; exports.modifyDelayM = modifyDelayM; exports.modifyDelayM_ = modifyDelayM_; exports.modifyDelay_ = modifyDelay_; exports.onDecision = onDecision; exports.onDecision_ = onDecision_; exports.once = void 0; exports.provideAll = provideAll; exports.provideAll_ = provideAll_; exports.provideSome = provideSome; exports.provideSome_ = provideSome_; exports.reconsider = reconsider; exports.reconsiderM = reconsiderM; exports.reconsiderM_ = reconsiderM_; exports.reconsider_ = reconsider_; exports.recurUntil = recurUntil; exports.recurUntilEquals = recurUntilEquals; exports.recurUntilM = recurUntilM; exports.recurWhile = recurWhile; exports.recurWhileEquals = recurWhileEquals; exports.recurWhileM = recurWhileM; exports.recurs = recurs; exports.repeat = repeat; exports.repetitions = repetitions; exports.resetAfter = resetAfter; exports.resetWhen = resetWhen; exports.resetWhen_ = resetWhen_; exports.right = right; exports.run = run; exports.run_ = run_; exports.second = second; exports.spaced = spaced; exports.stop = void 0; exports.succeed = succeed; exports.tapInput = tapInput; exports.tapInput_ = tapInput_; exports.tapOutput = tapOutput; exports.tapOutput_ = tapOutput_; exports.unfold = unfold; exports.unfoldM = unfoldM; exports.unfoldM_ = unfoldM_; exports.unfold_ = unfold_; exports.union = union; exports.unionWith = unionWith; exports.unionWith_ = unionWith_; exports.union_ = union_; exports.unit = unit; exports.untilInput = untilInput; exports.untilInputM = untilInputM; exports.untilInputM_ = untilInputM_; exports.untilInput_ = untilInput_; exports.untilOutput = untilOutput; exports.untilOutputM = untilOutputM; exports.untilOutputM_ = untilOutputM_; exports.untilOutput_ = untilOutput_; exports.whileInput = whileInput; exports.whileInputM = whileInputM; exports.whileInputM_ = whileInputM_; exports.whileInput_ = whileInput_; exports.whileOutput = whileOutput; exports.whileOutputM = whileOutputM; exports.whileOutputM_ = whileOutputM_; exports.whileOutput_ = whileOutput_; exports.windowed = windowed; exports.zip = zip; exports.zipLeft = zipLeft; exports.zipLeft_ = zipLeft_; exports.zipRight = zipRight; exports.zipRight_ = zipRight_; exports.zipWith = zipWith; exports.zipWith_ = zipWith_; exports.zip_ = zip_; var Clock = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Clock/index.js")); var A = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Collections/Immutable/Array/index.js")); var L = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Collections/Immutable/List/index.js")); var NA = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Collections/Immutable/NonEmptyArray/index.js")); var Tp = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Collections/Immutable/Tuple/index.js")); var E = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Either/index.js")); var _index7 = /*#__PURE__*/require("../Function/index.js"); var NoSuchElementException = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../GlobalExceptions/index.js")); var O = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Option/index.js")); var Random = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Random/index.js")); var R = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Ref/index.js")); var Decision = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./Decision/index.js")); var Driver = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./Driver/index.js")); var T = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./effect.js")); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } // ets_tracing: off /** * A `Schedule< Env, In, Out>` defines a recurring schedule, which consumes values of type `In`, and * which returns values of type `Out`. * * Schedules are defined as a possibly infinite set of intervals spread out over time. Each * interval defines a window in which recurrence is possible. * * When schedules are used to repeat or retry effects, the starting boundary of each interval * produced by a schedule is used as the moment when the effect will be executed again. * * Schedules compose in the following primary ways: * * * Union. This performs the union of the intervals of two schedules. * * Intersection. This performs the intersection of the intervals of two schedules. * * Sequence. This concatenates the intervals of one schedule onto another. * * In addition, schedule inputs and outputs can be transformed, filtered (to terminate a * schedule early in response to some input or output), and so forth. * * A variety of other operators exist for transforming and combining schedules, and the companion * object for `Schedule` contains all common types of schedules, both for performing retrying, as * well as performing repetition. */ class Schedule { constructor(step) { this.step = step; /** * Returns a new schedule that performs a geometric intersection on the intervals defined * by both schedules. */ this["&&"] = that => intersection_(this, that); /** * The same as `&&`, but ignores the left output. */ this["***"] = that => bothInOut_(this, that); /** * The same as `&&`, but ignores the left output. */ this["*>"] = that => map_(this["&&"](that), _ => _.get(1)); /** * Returns a new schedule that allows choosing between feeding inputs to this schedule, or * feeding inputs to the specified schedule. */ this["+++"] = that => chooseMerge_(this, that); /** * A symbolic alias for `andThen`. */ this["++"] = that => andThen_(this, that); /** * The same as `&&`, but ignores the right output. */ this["<*"] = that => map_(this["&&"](that), _ => _.get(0)); /** * An operator alias for `zip`. */ this["<*>"] = that => zip_(this, that); /** * Returns the composition of this schedule and the specified schedule, by piping the output of * this one into the input of the other. Effects described by this schedule will always be * executed before the effects described by the second schedule. */ this["<<<"] = that => compose_(that, this); /** * Returns the composition of this schedule and the specified schedule, by piping the output of * this one into the input of the other. Effects described by this schedule will always be * executed before the effects described by the second schedule. */ this[">>>"] = that => compose_(this, that); /** * Returns a new schedule that performs a geometric union on the intervals defined * by both schedules. */ this["||"] = that => union_(this, that); /** * Returns a new schedule that chooses between two schedules with a common output. */ this["|||"] = that => chooseMerge_(this, that); /** * Operator alias for `andThenEither`. */ this["<||>"] = that => andThenEither_(this, that); } } /** * Returns a driver that can be used to step the schedule, appropriately handling sleeping. */ exports.Schedule = Schedule; function driver(self) { return T.map_(R.makeRef([O.none, self.step]), ref => { const reset = ref.set([O.none, self.step]); const last = T.chain_(ref.get, ([o, _]) => O.fold_(o, () => T.fail(new NoSuchElementException.NoSuchElementException()), b => T.succeed(b))); const next = i => T.map_(T.bind_(T.bind_(T.bind_(T.bind_(T.do, "step", () => T.map_(ref.get, ([_, o]) => o)), "now", () => Clock.currentTime), "dec", ({ now, step }) => step(now, i)), "v", ({ dec, now }) => { switch (dec._tag) { case "Done": { return T.chain_(ref.set([O.some(dec.out), Decision.done(dec.out)]), () => T.fail(O.none)); } case "Continue": { return T.map_(T.chain_(T.map_(ref.set([O.some(dec.out), dec.next]), () => dec.interval - now), s => s > 0 ? T.sleep(s) : T.unit), () => dec.out); } } }), ({ v }) => v); return new Driver.Driver(next, last, reset); }); } function repeatLoop(init, self = init) { return (now, i) => T.chain_(self(now, i), d => { switch (d._tag) { case "Done": { return repeatLoop(init, self)(now, i); } case "Continue": { return T.succeed(Decision.makeContinue(d.out, d.interval, repeatLoop(init, d.next))); } } }); } /** * Returns a new schedule that loops this one continuously, resetting the state * when this schedule is done. */ function repeat(self) { return new Schedule(repeatLoop(self.step)); } /** * Returns a new schedule with the given delay added to every update. */ function addDelay(f) { return self => addDelayM_(self, b => T.succeed(f(b))); } /** * Returns a new schedule with the given delay added to every update. */ function addDelay_(self, f) { return addDelayM_(self, b => T.succeed(f(b))); } /** * Returns a new schedule with the effectfully calculated delay added to every update. */ function addDelayM(f) { return self => addDelayM_(self, f); } /** * Returns a new schedule with the effectfully calculated delay added to every update. */ function addDelayM_(self, f) { return modifyDelayM_(self, (o, d) => T.map_(f(o), i => i + d)); } /** * The same as `andThenEither`, but merges the output. */ function andThen(that) { return self => andThen_(self, that); } /** * The same as `andThenEither`, but merges the output. */ function andThen_(self, that) { return map_(andThenEither_(self, that), a => a._tag === "Left" ? a.left : a.right); } /** * Returns a new schedule that maps this schedule to a constant output. */ function as(o) { return self => map_(self, () => o); } function bothLoop(self, that) { return (now, t) => { const { tuple: [in1, in2] } = t; return T.zipWith_(self(now, in1), that(now, in2), (d1, d2) => { switch (d1._tag) { case "Done": { switch (d2._tag) { case "Done": { return Decision.makeDone(Tp.tuple(d1.out, d2.out)); } case "Continue": { return Decision.makeDone(Tp.tuple(d1.out, d2.out)); } } } case "Continue": { switch (d2._tag) { case "Done": { return Decision.makeDone(Tp.tuple(d1.out, d2.out)); } case "Continue": { return Decision.makeContinue(Tp.tuple(d1.out, d2.out), Math.min(d1.interval, d2.interval), bothLoop(d1.next, d2.next)); } } } } }); }; } /** * Returns a new schedule that has both the inputs and outputs of this and the specified * schedule. */ function bothInOut(that) { return self => new Schedule(bothLoop(self.step, that.step)); } /** * Returns a new schedule that has both the inputs and outputs of this and the specified * schedule. */ function bothInOut_(self, that) { return new Schedule(bothLoop(self.step, that.step)); } /** * Returns a new schedule that has both the inputs and outputs of this and the specified * schedule. */ function intersection(that) { return self => intersection_(self, that); } /** * Returns a new schedule that performs a geometric intersection on the intervals defined * by both schedules. */ function intersection_(self, that) { return intersectWith_(self, that, (l, r) => Math.max(l, r)); } /** * Returns a new schedule that passes each input and output of this schedule to the spefcified * function, and then determines whether or not to continue based on the return value of the * function. */ function check(f) { return self => check_(self, f); } /** * Returns a new schedule that passes each input and output of this schedule to the spefcified * function, and then determines whether or not to continue based on the return value of the * function. */ function check_(self, f) { return checkM_(self, (i, o) => T.succeed(f(i, o))); } function checkMLoop(self, test) { return (now, i) => T.chain_(self(now, i), d => { switch (d._tag) { case "Done": { return T.succeed(Decision.makeDone(d.out)); } case "Continue": { return T.map_(test(i, d.out), b => b ? Decision.makeContinue(d.out, d.interval, checkMLoop(d.next, test)) : Decision.makeDone(d.out)); } } }); } /** * Returns a new schedule that passes each input and output of this schedule to the specified * function, and then determines whether or not to continue based on the return value of the * function. */ function checkM(test) { return self => new Schedule(checkMLoop(self.step, test)); } /** * Returns a new schedule that passes each input and output of this schedule to the specified * function, and then determines whether or not to continue based on the return value of the * function. */ function checkM_(self, test) { return new Schedule(checkMLoop(self.step, test)); } /** * Returns a new schedule that first executes this schedule to completion, and then executes the * specified schedule to completion. */ function andThenEither(that) { return self => andThenEither_(self, that); } function andThenEitherLoop(self, that, onLeft) { return (now, i) => { if (onLeft) { return T.chain_(self(now, i), d => { switch (d._tag) { case "Continue": { return T.succeed(Decision.makeContinue(E.left(d.out), d.interval, andThenEitherLoop(d.next, that, true))); } case "Done": { return andThenEitherLoop(self, that, false)(now, i); } } }); } else { return T.map_(that(now, i), d => { switch (d._tag) { case "Done": { return Decision.makeDone(E.right(d.out)); } case "Continue": { return Decision.makeContinue(E.right(d.out), d.interval, andThenEitherLoop(self, d.next, false)); } } }); } }; } /** * Returns a new schedule that first executes this schedule to completion, and then executes the * specified schedule to completion. */ function andThenEither_(self, that) { return new Schedule(andThenEitherLoop(self.step, that.step, true)); } function chooseLoop(self, that) { return (now, either) => E.fold_(either, i => T.map_(self(now, i), d => { switch (d._tag) { case "Done": { return Decision.makeDone(E.left(d.out)); } case "Continue": { return Decision.makeContinue(E.left(d.out), d.interval, chooseLoop(d.next, that)); } } }), i2 => T.map_(that(now, i2), d => { switch (d._tag) { case "Done": { return Decision.makeDone(E.right(d.out)); } case "Continue": { return Decision.makeContinue(E.right(d.out), d.interval, chooseLoop(self, d.next)); } } })); } /** * Returns a new schedule that allows choosing between feeding inputs to this schedule, or * feeding inputs to the specified schedule. */ function choose(that) { return self => choose_(self, that); } /** * Returns a new schedule that allows choosing between feeding inputs to this schedule, or * feeding inputs to the specified schedule. */ function choose_(self, that) { return new Schedule(chooseLoop(self.step, that.step)); } /** * Returns a new schedule that allows choosing between feeding inputs to this schedule, or * feeding inputs to the specified schedule. */ function chooseMerge(that) { return self => chooseMerge_(self, that); } /** * Returns a new schedule that allows choosing between feeding inputs to this schedule, or * feeding inputs to the specified schedule. */ function chooseMerge_(self, that) { return map_(choose_(self, that), E.merge); } /** * Returns a new schedule that collects the outputs of this one into an array. */ function collectAll(self) { return map_(fold_(self, L.empty(), (xs, x) => L.append_(xs, x)), L.toArray); } /** * A schedule that recurs anywhere, collecting all inputs into a list. */ function collectAllIdentity() { return collectAll(identity()); } function composeLoop(self, that) { return (now, i) => T.chain_(self(now, i), d => { switch (d._tag) { case "Done": { return T.map_(that(now, d.out), Decision.toDone); } case "Continue": { return T.map_(that(now, d.out), d2 => { switch (d2._tag) { case "Done": { return Decision.makeDone(d2.out); } case "Continue": { return Decision.makeContinue(d2.out, Math.max(d.interval, d2.interval), composeLoop(d.next, d2.next)); } } }); } } }); } /** * Returns the composition of this schedule and the specified schedule, by piping the output of * this one into the input of the other. Effects described by this schedule will always be * executed before the effects described by the second schedule. */ function compose(that) { return self => compose_(self, that); } /** * Returns the composition of this schedule and the specified schedule, by piping the output of * this one into the input of the other. Effects described by this schedule will always be * executed before the effects described by the second schedule. */ function compose_(self, that) { return new Schedule(composeLoop(self.step, that.step)); } function intersectWithLoop(self, that, f) { return (now, i) => { const left = self(now, i); const right = that(now, i); return T.zipWith_(left, right, (l, r) => { switch (l._tag) { case "Done": { switch (r._tag) { case "Done": { return Decision.makeDone(Tp.tuple(l.out, r.out)); } case "Continue": { return Decision.makeDone(Tp.tuple(l.out, r.out)); } } } case "Continue": { switch (r._tag) { case "Done": { return Decision.makeDone(Tp.tuple(l.out, r.out)); } case "Continue": { return Decision.makeContinue(Tp.tuple(l.out, r.out), f(l.interval, r.interval), intersectWithLoop(l.next, r.next, f)); } } } } }); }; } /** * Returns a new schedule that deals with a narrower class of inputs than this schedule. */ function contramap(f) { return self => contramap_(self, f); } /** * Returns a new schedule that deals with a narrower class of inputs than this schedule. */ function contramap_(self, f) { return new Schedule((now, i) => T.map_(self.step(now, f(i)), Decision.contramap(f))); } /** * Returns a new schedule with the specified computed delay added before the start * of each interval produced by this schedule. */ function delayed(f) { return self => delayed_(self, f); } /** * Returns a new schedule with the specified computed delay added before the start * of each interval produced by this schedule. */ function delayedFrom(schedule) { return addDelay_(schedule, x => x); } /** * Returns a new schedule with the specified computed delay added before the start * of each interval produced by this schedule. */ function delayed_(self, f) { return delayedM_(self, d => T.succeed(f(d))); } /** * Returns a new schedule with the specified effectfully computed delay added before the start * of each interval produced by this schedule. */ function delayedM(f) { return self => delayedM_(self, f); } /** * Returns a new schedule with the specified effectfully computed delay added before the start * of each interval produced by this schedule. */ function delayedM_(self, f) { return modifyDelayM_(self, (o, d) => f(d)); } /** * Returns a new schedule that contramaps the input and maps the output. */ function dimap(f) { return g => self => dimap_(self, f, g); } /** * Returns a new schedule that contramaps the input and maps the output. */ function dimap_(self, f, g) { return map_(contramap_(self, f), g); } /** * A schedule that can recur one time, the specified amount of time into the future. */ function duration(n) { return new Schedule((now, _) => T.succeed(Decision.makeContinue(0, now + n, () => T.succeed(Decision.makeDone(n))))); } /** * A schedule that can recur one time, the specified amount of time into the future. */ function durations(n, ...rest) { return A.reduce_(rest, duration(n), (acc, d) => andThen_(acc, duration(d))); } /** * Returns a new schedule that performs a geometric union on the intervals defined * by both schedules. */ function union(that) { return self => union_(self, that); } /** * Returns a new schedule that combines this schedule with the specified * schedule, continuing as long as either schedule wants to continue and * merging the next intervals according to the specified merge function. */ function union_(self, that) { return unionWith_(self, that, (d1, d2) => Math.min(d1, d2)); } /** * Returns a new schedule that combines this schedule with the specified * schedule, continuing as long as either schedule wants to continue and * merging the next intervals according to the specified merge function. */ function unionWith(that, f) { return self => unionWith_(self, that, f); } function unionWithLoop(self, that, f) { return (now, inp) => { const left = self(now, inp); const right = that(now, inp); return T.zipWith_(left, right, (l, r) => { switch (l._tag) { case "Done": { switch (r._tag) { case "Done": { return Decision.makeDone(Tp.tuple(l.out, r.out)); } case "Continue": { return Decision.makeContinue(Tp.tuple(l.out, r.out), r.interval, unionWithLoop(() => T.succeed(l), r.next, f)); } } } case "Continue": { switch (r._tag) { case "Done": { return Decision.makeContinue(Tp.tuple(l.out, r.out), l.interval, unionWithLoop(l.next, () => T.succeed(r), f)); } case "Continue": { return Decision.makeContinue(Tp.tuple(l.out, r.out), f(l.interval, r.interval), unionWithLoop(l.next, r.next, f)); } } } } }); }; } /** * Returns a new schedule that combines this schedule with the specified * schedule, continuing as long as either schedule wants to continue and * merging the next intervals according to the specified merge function. */ function unionWith_(self, that, f) { return new Schedule(unionWithLoop(self.step, that.step, f)); } function elapsedLoop(o) { return (now, _) => T.succeed(O.fold_(o, () => Decision.makeContinue(0, now, elapsedLoop(O.some(now))), start => Decision.makeContinue(now - start, now, elapsedLoop(O.some(start))))); } /** * A schedule that occurs everywhere, which returns the total elapsed duration since the * first step. */ const elapsed = /*#__PURE__*/new Schedule( /*#__PURE__*/elapsedLoop(O.none)); /** * A schedule that always recurs, but will wait a certain amount between * repetitions, given by `base * factor.pow(n)`, where `n` is the number of * repetitions so far. Returns the current duration between recurrences. */ exports.elapsed = elapsed; function exponential(base, factor = 2.0) { return delayedFrom(map_(forever, i => base * Math.pow(factor, i))); } /** * A schedule that always recurs, increasing delays by summing the * preceding two delays (similar to the fibonacci sequence). Returns the * current duration between recurrences. */ function fibonacci(one) { return delayedFrom(map_(unfold_((0, _index7.tuple)(one, one), ([a1, a2]) => (0, _index7.tuple)(a1, a1 + a2)), ([_]) => _)); } /** * A schedule that recurs on a fixed interval. Returns the number of * repetitions of the schedule so far. * * If the action run between updates takes longer than the interval, then the * action will be run immediately, but re-runs will not "pile up". * * <pre> * |-----interval-----|-----interval-----|-----interval-----| * |---------action--------||action|-----|action|-----------| * </pre> */ function fixed(interval) { function loop(startMillis, n) { return (now, _) => T.succeed(O.fold_(startMillis, () => Decision.makeContinue(n + 1, now + interval, loop(O.some({ startMillis: now, lastRun: now + interval }), n + 1)), ({ lastRun, startMillis }) => { const runningBehind = now > lastRun + interval; const boundary = interval === 0 ? interval : interval - (now - startMillis) % interval; const sleepTime = boundary === 0 ? interval : boundary; const nextRun = runningBehind ? now : now + sleepTime; return Decision.makeContinue(n + 1, nextRun, loop(O.some({ startMillis, lastRun: nextRun }), n + 1)); })); } return new Schedule(loop(O.none, 0)); } /** * A schedule that always recurs, mapping input values through the * specified function. */ function fromFunction(f) { return map_(identity(), f); } /** * A schedule that always recurs, which counts the number of recurrances. */ const count = /*#__PURE__*/unfold_(0, n => n + 1); exports.count = count; function ensuringLoop(finalizer, self) { return (now, i) => T.chain_(self(now, i), d => { switch (d._tag) { case "Done": { return T.as_(finalizer, Decision.makeDone(d.out)); } case "Continue": { return T.succeed(Decision.makeContinue(d.out, d.interval, ensuringLoop(finalizer, d.next))); } } }); } /** * Returns a new schedule that will run the specified finalizer as soon as the schedule is * complete. Note that unlike `Effect#ensuring`, this method does not guarantee the finalizer * will be run. The `Schedule` may not initialize or the driver of the schedule may not run * to completion. However, if the `Schedule` ever decides not to continue, then the * finalizer will be run. */ function ensuring(finalizer) { return self => new Schedule(ensuringLoop(finalizer, self.step)); } /** * Returns a new schedule that will run the specified finalizer as soon as the schedule is * complete. Note that unlike `Effect#ensuring`, this method does not guarantee the finalizer * will be run. The `Schedule` may not initialize or the driver of the schedule may not run * to completion. However, if the `Schedule` ever decides not to continue, then the * finalizer will be run. */ function ensuring_(self, finalizer) { return new Schedule(ensuringLoop(finalizer, self.step)); } /** * Returns a new schedule that packs the input and output of this schedule into the first * element of a tuple. This allows carrying information through this schedule. */ function first() { return self => bothInOut_(self, identity()); } function foldMLoop(z, f, self) { return (now, i) => T.chain_(self(now, i), d => { switch (d._tag) { case "Done": { return T.succeed(Decision.makeDone(z)); } case "Continue": { return T.map_(f(z, d.out), z2 => Decision.makeContinue(z2, d.interval, foldMLoop(z2, f, d.next))); } } }); } /** * Returns a new schedule that effectfully folds over the outputs of this one. */ function fold(z) { return f => self => fold_(self, z, f); } /** * Returns a new schedule that effectfully folds over the outputs of this one. */ function fold_(self, z, f) { return foldM_(self, z, (z, o) => T.succeed(f(z, o))); } /** * Returns a new schedule that effectfully folds over the outputs of this one. */ function foldM(z) { return f => self => foldM_(self, z, f); } /** * Returns a new schedule that effectfully folds over the outputs of this one. */ function foldM_(self, z, f) { return new Schedule(foldMLoop(z, f, self.step)); } /** * A schedule that recurs forever, producing a count of repeats: 0, 1, 2, ... */ const forever = /*#__PURE__*/unfold_(0, n => n + 1); exports.forever = forever; function identityLoop() { return (now, i) => T.succeed(Decision.makeContinue(i, now, identityLoop())); } /** * A schedule that always recurs, which returns inputs as outputs. */ function identity() { return new Schedule(identityLoop()); } /** * Returns a new schedule that combines this schedule with the specified * schedule, continuing as long as both schedules want to continue and * merging the next intervals according to the specified merge function. */ function intersectWith_(self, that, f) { return new Schedule(intersectWithLoop(self.step, that.step, f)); } /** * Returns a new schedule that combines this schedule with the specified * schedule, continuing as long as both schedules want to continue and * merging the next intervals according to the specified merge function. */ function intersectWith(that, f) { return self => intersectWith_(self, that, f); } /** * Returns a new schedule that randomly modifies the size of the intervals of this schedule. */ function jittered({ max = 0.1, min = 0 } = {}) { return self => jittered_(self, { min, max }); } /** * Returns a new schedule that randomly modifies the size of the intervals of this schedule. */ function jittered_(self, { max = 0.1, min = 0 } = {}) { return delayedM_(self, d => T.map_(Random.next, random => d * min * (1 - random) + d * max * random)); } /** * A schedule that always recurs, but will repeat on a linear time * interval, given by `base * n` where `n` is the number of * repetitions so far. Returns the current duration between recurrences. */ function linear(base) { return delayedFrom(map_(forever, i => base * (i + 1))); } /** * A schedule that recurs one time. */ const once = /*#__PURE__*/unit( /*#__PURE__*/recurs(1)); exports.once = once; function mapMLoop(f, self) { return (now, i) => T.chain_(self(now, i), d => { switch (d._tag) { case "Done": { return T.map_(f(d.out), o => Decision.makeDone(o)); } case "Continue": { return T.map_(f(d.out), o => Decision.makeContinue(o, d.interval, mapMLoop(f, d.next))); } } }); } /** * Returns a new schedule that makes this schedule available on the `Left` side of an `Either` * input, allowing propagating some type `X` through this channel on demand. */ function left() { return self => choose_(self, identity()); } /** * Returns a new schedule that maps the output of this schedule through the specified * effectful function. */ function map(f) { return self => map_(self, f); } /** * Returns a new schedule that maps the output of this schedule through the specified * effectful function. */ function map_(self, f) { return mapM_(self, o => T.succeed(f(o))); } /** * Returns a new schedule that maps the output of this schedule through the specified function. */ function mapM(f) { return self => new Schedule(mapMLoop(f, self.step)); } /** * Returns a new schedule that maps the output of this schedule through the specified function. */ function mapM_(self, f) { return new Schedule(mapMLoop(f, self.step)); } function modifyDelayMLoop(f, self) { return (now, i) => T.chain_(self(now, i), d => { switch (d._tag) { case "Done": { return T.succeed(Decision.makeDone(d.out)); } case "Continue": { const delay = d.interval - now; return T.map_(f(d.out, delay), n => Decision.makeContinue(d.out, d.interval + n, modifyDelayMLoop(f, d.next))); } } }); } /** * Returns a new schedule that modifies the delay using the specified * effectual function. */ function modifyDelayM(f) { return self => modifyDelayM_(self, f); } /** * Returns a new schedule that modifies the delay using the specified * effectual function. */ function modifyDelayM_(self, f) { return new Schedule(modifyDelayMLoop(f, self.step)); } /** * Returns a new schedule that modifies the delay using the specified * function. */ function modifyDelay(f) { return self => modifyDelay_(self, f); } /** * Returns a new schedule that modifies the delay using the specified * function. */ function modifyDelay_(self, f) { return modifyDelayM_(self, (o, d) => T.succeed(f(o, d))); } function onDecisionLoop(self, f) { return (now, i) => T.chain_(self(now, i), d => { switch (d._tag) { case "Done": { return T.as_(f(d), Decision.makeDone(d.out)); } case "Continue": { return T.as_(f(d), Decision.makeContinue(d.out, d.interval, onDecisionLoop(d.next, f))); } } }); } /** * Returns a new schedule that applies the current one but runs the specified effect * for every decision of this schedule. This can be used to create schedules * that log failures, decisions, or computed values. */ function onDecision_(self, f) { return new Schedule(onDecisionLoop(self.step, f)); } /** * Returns a new schedule that applies the current one but runs the specified effect * for every decision of this schedule. This can be used to create schedules * that log failures, decisions, or computed values. */ function onDecision(f) { return self => new Schedule(onDecisionLoop(self.step, f)); } function provideAllLoop(env, self) { return (now, i) => T.provideAll_(T.map_(self(now, i), d => { switch (d._tag) { case "Done": { return Decision.makeDone(d.out); } case "Continue": { return Decision.makeContinue(d.out, d.interval, provideAllLoop(env, d.next)); } } }), env); } /** * Returns a new schedule with its environment provided to it, so the resulting * schedule does not require any environment. */ function provideAll(env) { return self => provideAll_(self, env); } /** * Returns a new schedule with its environment provided to it, so the resulting * schedule does not require any environment. */ function provideAll_(self, env) { return new Schedule(provideAllLoop(env, self.step)); } function provideSomeLoop(env, self) { return (now, i) => T.provideSome_(T.map_(self(now, i), d => { switch (d._tag) { case "Done": { return Decision.makeDone(d.out); } case "Continue": { return Decision.makeContinue(d.out, d.interval, provideSomeLoop(env, d.next)); } } }), env); } /** * Returns a new schedule with part of its environment provided to it, so the * resulting schedule does not require any environment. */ function provideSome(env) { return self => new Schedule(provideSomeLoop(env, self.step)); } /** * Returns a new schedule with part of its environment provided to it, so the * resulting schedule does not require any environment. */ function provideSome_(self, env) { return new Schedule(provideSomeLoop(env, self.step)); } /** * Returns a new schedule that effectfully reconsiders every decision made by this schedule, * possibly modifying the next interval and the output type in the process. */ function reconsider(f) { return self => reconsider_(self, f); } /** * Returns a new schedule that effectfully reconsiders every decision made by this schedule, * possibly modifying the next interval and the output type in the process. */ function reconsider_(self, f) { return reconsiderM_(self, d => T.succeed(f(d))); } function reconsiderMLoop(self, f) { return (now, i) => T.chain_(self(now, i), d => { switch (d._tag) { case "Done": { return T.map_(f(d), E.fold(o2 => Decision.makeDone(o2), ([o2]) => Decision.makeDone(o2))); } case "Continue": { return T.map_(f(d), E.fold(o2 => Decision.makeDone(o2), ([o2, int]) => Decision.makeContinue(o2, int, reconsiderMLoop(d.next, f)))); } } }); } /** * Returns a new schedule that effectfully reconsiders every decision made by this schedule, * possibly modifying the next interval and the output type in the process. */ function reconsiderM(f) { return self => reconsiderM_(self, f); } /** * Returns a new schedule that effectfully reconsiders every decision made by this schedule, * possibly modifying the next interval and the output type in the process. */ function reconsiderM_(self, f) { return new Schedule(reconsiderMLoop(self.step, f)); } /** * Returns a new schedule that outputs the number of repetitions of this one. */ function repetitions(self) { return fold_(self, 0, n => n + 1); } /** * Return a new schedule that automatically resets the schedule to its initial state * after some time of inactivity defined by `duration`. */ function resetAfter(duration) { return self => map_(resetWhen_(zip_(self, elapsed), ({ tuple: [_, d] }) => d >= duration), ({ tuple: [o] }) => o); } function resetWhenLoop(self, step, f) { return (now, i) => T.chain_(step(now, i), d => { switch (d._tag) { case "Done": { return f(d.out) ? self.step(now, i) : T.succeed(Decision.makeDone(d.out)); } case "Continue": { return f(d.out) ? self.step(now, i) : T.succeed(Decision.makeContinue(d.out, d.interval, resetWhenLoop(self, d.next, f))); } } }); } /** * Resets the schedule when the specified predicate on the schedule output evaluates to true. */ function resetWhen(f) { return self => resetWhen_(self, f); } /** * Resets the schedule when the specified predicate on the schedule output evaluates to true. */ function resetWhen_(self, f) { return new Schedule(resetWhenLoop(self, self.step, f)); } /** * A schedule that recurs for as long as the predicate evaluates to true. */ function recurWhile(f) { return whileInput_(identity(), f); } /** * A schedule that recurs for as long as the effectful predicate evaluates to true. */ function recurWhileM(f) { return whileInputM_(identity(), f); } /** * A schedule that recurs for as long as the predicate evaluates to true. */ function recurWhileEquals(a) { return whileInput_(identity(), x => a === x); } /** * A schedule that recurs for as long as the predicate evaluates to true. */ function recurUntil(f) { return untilInput_(identity(), f); } /** * A schedule that recurs for as long as the effectful predicate evaluates to true. */ function recurUntilM(f) { return untilInputM_(identity(), f); } /** * A schedule that recurs for as long as the predicate evaluates to true. */ function recurUntilEquals(a) { return untilInput_(identity(), x => x === a); } /** * A schedule spanning all time, which can be stepped only the specified number of times before * it terminates. */ function recurs(n) { return whileOutput_(forever, x => x < n); } /** * Returns a new schedule that makes this schedule available on the `Right` side of an `Either` * input, allowing propagating some type `X` through this channel on demand. */ function right() { return self => choose_(identity(), self); } function runLoop(now, xs, self, acc) { if (A.isNonEmpty(xs)) { return T.chain_(self(now, NA.head(xs)), d => { switch (d._tag) { case "Done": { return T.succeed([...acc, d.out]); } case "Continue": { return runLoop(d.interval, xs, d.next, [...acc, d.out]); } } }); } else { return T.succeed(acc); } } /** * Runs a schedule using the provided inputs, and collects all outputs. */ function run(now, i) { return self => run_(self, now, i); } /** * Runs a schedule using the provided inputs, and collects all outputs. */ function run_(self, now, i) { return runLoop(now, Array.from(i), self.step, []); } /** * Returns a new schedule that packs the input and output of this schedule into the second * element of a tuple. This allows carrying information through this schedule. */ function second() { return self => bothInOut_(identity(), self); } function tapInputLoop(self, f) { return (now, i) => T.chain_(f(i), () => T.map_(self(now, i), d => { switch (d._tag) { case "Done": { return Decision.makeDone(d.out); } case "Continue": { return Decision.makeContinue(d.out, d.interval, tapInputLoop(d.next, f)); } } })); } /** * Returns a schedule that recurs continuously, each repetition spaced the specified duration * from the last run. */ function spaced(duration) { return addDelay_(forever, () => duration); } /** * A schedule that does not recur, it just stops. */ const stop = /*#__PURE__*/unit( /*#__PURE__*/recurs(0)); /** * Returns a schedule that repeats one time, producing the specified constant value. */ exports.stop = stop; function succeed(a) { return as(a)(forever); } /** * Returns a new schedule that effectfully processes every input to this schedule. */ function tapInput_(self, f) { return new Schedule(tapInputLoop(self.step, f)); } /** * Returns a new schedule that effectfully processes every input to this schedule. */ function tapInput(f) { return self => new Schedule(tapInputLoop(self.step, f)); } function tapOutputLoop(self, f) { return (now, i) => T.chain_(self(now, i), d => { switch (d._tag) { case "Done": { return T.as_(f(d.out), Decision.makeDone(d.out)); } case "Continue": { return T.as_(f(d.out), Decision.makeContinue(d.out, d.interval, tapOutputLoop(d.next, f))); } } }); } /** * Returns a new schedule that effectfully processes every output from this schedule. */ function tapOutput(f) { return self => tapOutput_(self, f); } /** * Returns a new schedule that effectfully processes every output from this schedule. */ function tapOutput_(self, f) { return new Schedule(tapOutputLoop(self.step, f)); } /** * Returns a new schedule that maps the output of this schedule to unit. */ function unit(self) { return as(undefined)(self); } /** * Returns a new schedule that continues until the specified predicate on the input evaluates * to true. */ function untilInput(f) { return self => untilInput_(self, f); } /** * Returns a new schedule that continues until the specified predicate on the input evaluates * to true. */ function untilInput_(self, f) { return check_(self, i => !f(i)); } /** * Returns a new schedule that continues until the specified effectful predicate on the input * evaluates to true. */ function untilInputM(f) { return self => untilInputM_(self, f); } /** * Returns a new schedule that continues until the specified effectful predicate on the input * evaluates to true. */ function untilInputM_(self, f) { return checkM_(self, i => T.map_(f(i), b => !b)); } /** * Returns a new schedule that continues until the specified predicate on the input evaluates * to true. */ function untilOutput(f) { return self => untilOutput_(self, f); } /** * Returns a new schedule that continues until the specified predicate on the input evaluates * to true. */ function untilOutput_(self, f) { return check_(self, (_, o) => !f(o)); } /** * Returns a new schedule that continues until the specified predicate on the input evaluates * to true. */ function untilOutputM(f) { return self => untilOutputM_(self, f); } /** * Returns a new schedule that continues until the specified predicate on the input evaluates * to true. */ function untilOutputM_(self, f) { return checkM_(self, (_, o) => T.map_(f(o), b => !b)); } /** * Returns a new schedule that continues for as long the specified predicate on the input * evaluates to true. */ function whileInput(f) { return self => whileInput_(self, f); } /** * Returns a new schedule that continues for as long the specified predicate on the input * evaluates to true. */ function whileInput_(self, f) { return check_(self, i => f(i)); } /** * Returns a new schedule that continues for as long the specified effectful predicate on the * input evaluates to true. */ function whileInputM(f) { return self => whileInputM_(self, f); } /** * Returns a new schedule that continues for as long the specified effectful predicate on the * input evaluates to true. */ function whileInputM_(self, f) { return checkM_(self, i => f(i)); } /** * Returns a new schedule that continues for as long the specified predicate on the output * evaluates to true. */ function whileOutput(f) { return self => whileOutput_(self, f); } /** * Returns a new schedule that continues for as long the specified predicate on the output * evaluates to true. */ function whileOutput_(self, f) { return check_(self, (_, o) => f(o)); } /** * Returns a new schedule that continues for as long the specified effectful predicate on the * output evaluates to true. */ function whileOutputM(f) { return self => whileOutputM_(self, f); } /** * Returns a new schedule that continues for as long the specified effectful predicate on the * output evaluates to true. */ function whileOutputM_(self, f) { return checkM_(self, (_, o) => T.map_(f(o), b => !b)); } function windowedLoop(interval, startMillis, n) { return (now, _) => T.succeed(O.fold_(startMillis, () => Decision.makeContinue(n + 1, now + interval, windowedLoop(interval, O.some(now), n + 1)), startMillis => { return Decision.makeContinue(n + 1, now + (interval - (now - startMillis) % interval), windowedLoop(interval, O.some(startMillis), n + 1)); })); } /** * A schedule that divides the timeline to `interval`-long windows, and sleeps * until the nearest window boundary every time it recurs. * * For example, `windowed(10_000)` would produce a schedule as follows: * <pre> * 10s 10s 10s 10s * |----------|----------|----------|----------| * |action------|sleep---|act|-sleep|action----| * </pre> */ function windowed(interval) { return new Schedule(windowedLoop(interval, O.none, 0)); } function unfoldLoop(a, f) { return (now, _) => T.succeed(Decision.makeContinue(a, now, unfoldLoop(f(a), f))); } /** * Unfolds a schedule that repeats one time from the specified state and iterator. */ function