import { unsafeForkUnstarted } from "@effect/core/io/Fiber/_internal/runtime" /** * Forks this effect and the specified effect into their own fibers, and races * them, calling one of two specified callbacks depending on which fiber wins * the race. This method does not interrupt, join, or otherwise do anything * with the fibers. It can be considered a low-level building block for * higher-level operators like `race`. * * @tsplus static effect/core/io/Effect.Aspects raceFibersWith * @tsplus pipeable effect/core/io/Effect raceFibersWith */ export function raceFibersWith( that: Effect, selfWins: (winner: Fiber, loser: Fiber) => Effect, thatWins: (winner: Fiber, loser: Fiber) => Effect ): (self: Effect) => Effect< R | R1 | R2 | R3, E2 | E3, A2 | A3 > { return (self) => Effect.withFiberRuntime((parentState, parentStatus) => { const parentRuntimeFlags = parentStatus.runtimeFlags const raceIndicator = new AtomicBoolean(true) const leftFiber = unsafeForkUnstarted(self, parentState, parentRuntimeFlags) const rightFiber = unsafeForkUnstarted(that, parentState, parentRuntimeFlags) leftFiber.setFiberRef(FiberRef.forkScopeOverride, Maybe.some(parentState.scope)) rightFiber.setFiberRef(FiberRef.forkScopeOverride, Maybe.some(parentState.scope)) return Effect.asyncBlockingOn((cb) => { leftFiber.addObserver(() => complete(leftFiber, rightFiber, selfWins, raceIndicator, cb)) rightFiber.addObserver(() => complete(rightFiber, leftFiber, thatWins, raceIndicator, cb)) leftFiber.startFork(self) rightFiber.startFork(that) }, FiberId.combineAll(HashSet.from([leftFiber.id, rightFiber.id]))) }) } function complete( winner: Fiber, loser: Fiber, cont: (winner: Fiber, loser: Fiber) => Effect, ab: AtomicReference, cb: (_: Effect) => void ): void { if (ab.compareAndSet(true, false)) { cb(cont(winner, loser)) } }