Commit fd01e2ae by Vladislav Lagunoff

[eff] Исправлена ошибка в обработке Chain

parent 1fdae3a5
...@@ -17,6 +17,8 @@ export type Eff<Error, Success> = ...@@ -17,6 +17,8 @@ export type Eff<Error, Success> =
| Apply<Error, Success> // { args: Eff<unknown>[], proj(...args): Either<Error, Success> } | Apply<Error, Success> // { args: Eff<unknown>[], proj(...args): Either<Error, Success> }
| Chain<Error, Success> // { first: Eff<unknown>, andThen(x: unknown): Eff<Error, Success> } | Chain<Error, Success> // { first: Eff<unknown>, andThen(x: unknown): Eff<Error, Success> }
| HasEffect<Error, Success> // { toEffect(): Eff<Error, Success> } | HasEffect<Error, Success> // { toEffect(): Eff<Error, Success> }
;
export type AnyEff = Eff<any, any>;
// Instance methods for `Eff` // Instance methods for `Eff`
...@@ -140,7 +142,7 @@ export function ap(): Eff<unknown, unknown> { ...@@ -140,7 +142,7 @@ export function ap(): Eff<unknown, unknown> {
} }
export function record<R extends Record<string, Eff<any, any>>>(rec: R): Eff<{ [K in keyof R]: R[K]['_Error'] }[keyof R], { [K in keyof R]: R[K]['_Success'] }> { export function record<R extends Record<string, AnyEff>>(rec: R): Eff<{ [K in keyof R]: R[K]['_Error'] }[keyof R], { [K in keyof R]: R[K]['_Success'] }> {
const keys = Object.keys(rec); const keys = Object.keys(rec);
return ap.apply(undefined, [...keys.map(k => rec[k]), (...values) => values.reduce((acc, v, idx) => (acc[keys[idx]] = v, acc), {})]); return ap.apply(undefined, [...keys.map(k => rec[k]), (...values) => values.reduce((acc, v, idx) => (acc[keys[idx]] = v, acc), {})]);
} }
...@@ -240,23 +242,27 @@ export function go<Error, Success>(effect: Eff<Error, Success>, onNext: (x: Eith ...@@ -240,23 +242,27 @@ export function go<Error, Success>(effect: Eff<Error, Success>, onNext: (x: Eith
} }
if (effect instanceof Chain) { if (effect instanceof Chain) {
const subscriptions: Array<Function|null> = []; const cancellers = new Map<AnyEff, Canceller>();
subscriptions.push(go(effect.first, result => { const handleEffect = (e: AnyEff) => {
const idx = subscriptions.length; const _onNext = result => {
subscriptions.push(go(effect.andThen(result), onNext, () => { if (e === effect.first) handleEffect(effect.andThen(result));
subscriptions[idx] = null; else onNext(result);
for (const unsub of subscriptions) if (unsub !== null) return; };
onComplete(); const _onComplete = () => {
})); if (!cancellers.has(e)) completedImmediately = true;
}, () => { cancellers.delete(e);
subscriptions[0] = null; if (cancellers.size === 0) onComplete();
for (const unsub of subscriptions) if (unsub !== null) return; };
onComplete(); let completedImmediately = false;
}));
const canceller = go(e, _onNext, _onComplete);
if (!completedImmediately) cancellers.set(e, canceller);
};
handleEffect(effect.first);
if (cancellers.size === 0) return noopFunc;
return () => subscriptions.forEach( return () => cancellers.forEach(canceller => canceller());
funOrNull => funOrNull ? funOrNull() : void 0
);
} }
if (effect instanceof Apply) { if (effect instanceof Apply) {
...@@ -355,6 +361,9 @@ export abstract class HasEffect<Error, Success> extends EffBase<Error, Success> ...@@ -355,6 +361,9 @@ export abstract class HasEffect<Error, Success> extends EffBase<Error, Success>
export const noop: Cmd<never> = new Batch([]); export const noop: Cmd<never> = new Batch([]);
export type Canceller = () => void;
export interface EffStatics { export interface EffStatics {
of: typeof of, of: typeof of,
success: typeof success, success: typeof success,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment