Skip to content

Commit

Permalink
add Semaphore.withPermitsIfAvailable (#3593)
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-smart committed Sep 13, 2024
1 parent fd08152 commit f4dc18e
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 0 deletions.
21 changes: 21 additions & 0 deletions .changeset/few-mayflies-speak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
"effect": minor
---

add Semaphore.withPermitsIfAvailable

You can now use `Semaphore.withPermitsIfAvailable` to run an Effect only if the
Semaphore has enough permits available. This is useful when you want to run an
Effect only if you can acquire a permit without blocking.

It will return an `Option.Some` with the result of the Effect if the permits were
available, or `None` if they were not.

```ts
import { Effect } from "effect"

Effect.gen(function* () {
const semaphore = yield* Effect.makeSemaphore(1)
semaphore.withPermitsIfAvailable(1)(Effect.void)
})
```
2 changes: 2 additions & 0 deletions packages/effect/src/Effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5374,6 +5374,8 @@ export interface Permit {
export interface Semaphore {
/** when the given amount of permits are available, run the effect and release the permits when finished */
withPermits(permits: number): <A, E, R>(self: Effect<A, E, R>) => Effect<A, E, R>
/** only if the given permits are available, run the effect and release the permits when finished */
withPermitsIfAvailable(permits: number): <A, E, R>(self: Effect<A, E, R>) => Effect<Option.Option<A>, E, R>
/** take the given amount of permits, suspending if they are not yet available */
take(permits: number): Effect<number>
/** release the given amount of permits, and return the resulting available permits */
Expand Down
11 changes: 11 additions & 0 deletions packages/effect/src/internal/effect/circular.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ class Semaphore {
(permits) => fiberRuntime.ensuring(restore(self), this.release(permits))
)
)

readonly withPermitsIfAvailable = (n: number) => <A, E, R>(self: Effect.Effect<A, E, R>) =>
core.uninterruptibleMask((restore) =>
core.suspend(() => {
if (this.free < n) {
return effect.succeedNone
}
this.taken += n
return fiberRuntime.ensuring(restore(effect.asSome(self)), this.release(n))
})
)
}

/** @internal */
Expand Down

0 comments on commit f4dc18e

Please sign in to comment.