diff --git a/.changeset/early-poems-explode.md b/.changeset/early-poems-explode.md new file mode 100644 index 0000000000..9817262db3 --- /dev/null +++ b/.changeset/early-poems-explode.md @@ -0,0 +1,5 @@ +--- +"effect": minor +--- + +`Latch` implements `Effect` with `.await` semantic diff --git a/packages/effect/dtslint/Unify.ts b/packages/effect/dtslint/Unify.ts index 926da4eb36..734093ffe3 100644 --- a/packages/effect/dtslint/Unify.ts +++ b/packages/effect/dtslint/Unify.ts @@ -125,7 +125,7 @@ export type ResourceUnify = Unify.Unify< | Resource.Resource > -// $ExpectType 0 | Option | Ref<1> | SynchronizedRef<1> | SubscriptionRef<1> | Deferred<1, 2> | Deferred<"a", "b"> | Fiber<"a" | 1, "b" | 2> | RuntimeFiber<"a" | 1, "b" | 2> | Queue<1> | Queue<"a"> | Dequeue<"a" | 1> | ScopedRef<1> | ScopedRef<"a"> | Resource<1, 2> | Ref<"A"> | SynchronizedRef<"A"> | SubscriptionRef<"A"> | FiberRef<12> | FiberRef<"a2"> | Resource<"a", never> | Either<1 | "A", 0 | "E"> | Effect<1 | "A", 0 | "E", "R" | "R1"> | RcRef<1 | "A", 0 | "E"> +// $ExpectType 0 | Option | Ref<1> | SynchronizedRef<1> | SubscriptionRef<1> | Deferred<1, 2> | Deferred<"a", "b"> | Fiber<"a" | 1, "b" | 2> | RuntimeFiber<"a" | 1, "b" | 2> | Queue<1> | Queue<"a"> | Dequeue<"a" | 1> | ScopedRef<1> | ScopedRef<"a"> | Resource<1, 2> | Ref<"A"> | SynchronizedRef<"A"> | SubscriptionRef<"A"> | FiberRef<12> | FiberRef<"a2"> | Resource<"a", never> | Latch | Either<1 | "A", 0 | "E"> | Effect<1 | "A", 0 | "E", "R" | "R1"> | RcRef<1 | "A", 0 | "E"> export type AllUnify = Unify.Unify< | Either.Either<1, 0> | Either.Either<"A", "E"> @@ -157,5 +157,6 @@ export type AllUnify = Unify.Unify< | ScopedRef.ScopedRef<"a"> | Resource.Resource<1, 2> | Resource.Resource<"a"> + | Effect.Latch | 0 > diff --git a/packages/effect/src/Effect.ts b/packages/effect/src/Effect.ts index 090039deb2..ca890bbb2d 100644 --- a/packages/effect/src/Effect.ts +++ b/packages/effect/src/Effect.ts @@ -5408,7 +5408,7 @@ export const makeSemaphore: (permits: number) => Effect = circular.ma * @category latch * @since 3.8.0 */ -export interface Latch { +export interface Latch extends Effect { /** open the latch, releasing all fibers waiting on it */ readonly open: Effect /** release all fibers waiting on the latch, without opening it */ @@ -5419,6 +5419,26 @@ export interface Latch { readonly close: Effect /** only run the given effect when the latch is open */ readonly whenOpen: (self: Effect) => Effect + + readonly [Unify.typeSymbol]?: unknown + readonly [Unify.unifySymbol]?: LatchUnify + readonly [Unify.ignoreSymbol]?: LatchUnifyIgnore +} + +/** + * @category models + * @since 3.8.0 + */ +export interface LatchUnify extends EffectUnify { + Latch?: () => Latch +} + +/** + * @category models + * @since 3.8.0 + */ +export interface LatchUnifyIgnore extends EffectUnifyIgnore { + Effect?: true } /** diff --git a/packages/effect/src/internal/effect/circular.ts b/packages/effect/src/internal/effect/circular.ts index 53a75fea5c..4b700fd963 100644 --- a/packages/effect/src/internal/effect/circular.ts +++ b/packages/effect/src/internal/effect/circular.ts @@ -112,10 +112,16 @@ export const unsafeMakeSemaphore = (permits: number): Semaphore => new Semaphore /** @internal */ export const makeSemaphore = (permits: number) => core.sync(() => unsafeMakeSemaphore(permits)) -class Latch implements Effect.Latch { +class Latch extends Effectable.Class implements Effect.Latch { waiters: Array<(_: Effect.Effect) => void> = [] scheduled = false - constructor(private isOpen: boolean) {} + constructor(private isOpen: boolean) { + super() + } + + commit() { + return this.await + } private unsafeSchedule(fiber: Fiber.RuntimeFiber) { if (this.scheduled || this.waiters.length === 0) { diff --git a/packages/effect/test/Effect/latch.test.ts b/packages/effect/test/Effect/latch.test.ts index e85d56184e..019cd8c8d9 100644 --- a/packages/effect/test/Effect/latch.test.ts +++ b/packages/effect/test/Effect/latch.test.ts @@ -30,4 +30,14 @@ describe("Latch", () => { yield* latch.release assert.deepStrictEqual(yield* fiber.await, Exit.void) })) + + it.effect("subtype of Effect", () => + Effect.gen(function*() { + const latch = yield* Effect.makeLatch() + const fiber = yield* Effect.fork(latch) + + yield* latch.open + + assert.deepStrictEqual(yield* fiber.await, Exit.void) + })) })