Skip to content

Commit

Permalink
make Fiber subtype of Effect (#3590)
Browse files Browse the repository at this point in the history
Co-authored-by: maksim.khramtsov <[email protected]>
  • Loading branch information
2 people authored and tim-smart committed Sep 13, 2024
1 parent 9303a09 commit d2e5807
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 76 deletions.
16 changes: 16 additions & 0 deletions .changeset/seven-lamps-nail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"effect": minor
---

The `Fiber<A, E>` is now a subtype of `Effect<A, E>`. This change removes the need for explicit call `Fiber.join`.

```typescript
import { Effect, Fiber } from "effect"

Effect.gen(function*() {
const fiber = yield* Effect.fork(Effect.succeed(1))

const oldWay = yield* Fiber.join(fiber)
const now = yield* fiber
}))
```
17 changes: 16 additions & 1 deletion packages/effect/dtslint/Unify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type * as Deferred from "effect/Deferred"
import type * as Effect from "effect/Effect"
import * as Either from "effect/Either"
import type * as Exit from "effect/Exit"
import type * as Fiber from "effect/Fiber"
import type * as FiberRef from "effect/FiberRef"
import type * as Micro from "effect/Micro"
import type * as Option from "effect/Option"
Expand Down Expand Up @@ -78,8 +79,18 @@ export type FiberRefUnify = Unify.Unify<
| FiberRef.FiberRef<1>
| FiberRef.FiberRef<"a">
>
// $ExpectType Fiber<"a" | 1, "b" | 2>
export type FiberUnify = Unify.Unify<
| Fiber.Fiber<1, 2>
| Fiber.Fiber<"a", "b">
>
// $ExpectType RuntimeFiber<"a" | 1, "b" | 2>
export type RuntimeFiberUnify = Unify.Unify<
| Fiber.RuntimeFiber<1, 2>
| Fiber.RuntimeFiber<"a", "b">
>

// $ExpectType 0 | Option<string | number> | Ref<1> | SynchronizedRef<1> | SubscriptionRef<1> | Deferred<1, 2> | Deferred<"a", "b"> | Ref<"A"> | SynchronizedRef<"A"> | SubscriptionRef<"A"> | FiberRef<12> | FiberRef<"a2"> | Either<1 | "A", 0 | "E"> | Effect<1 | "A", 0 | "E", "R" | "R1"> | RcRef<1 | "A", 0 | "E">
// $ExpectType 0 | Option<string | number> | Ref<1> | SynchronizedRef<1> | SubscriptionRef<1> | Deferred<1, 2> | Deferred<"a", "b"> | Fiber<"a" | 1, "b" | 2> | RuntimeFiber<"a" | 1, "b" | 2> | Ref<"A"> | SynchronizedRef<"A"> | SubscriptionRef<"A"> | FiberRef<12> | FiberRef<"a2"> | 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">
Expand All @@ -99,5 +110,9 @@ export type AllUnify = Unify.Unify<
| Deferred.Deferred<"a", "b">
| FiberRef.FiberRef<12>
| FiberRef.FiberRef<"a2">
| Fiber.Fiber<1, 2>
| Fiber.Fiber<"a", "b">
| Fiber.RuntimeFiber<1, 2>
| Fiber.RuntimeFiber<"a", "b">
| 0
>
45 changes: 43 additions & 2 deletions packages/effect/src/Fiber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ import * as internal from "./internal/fiber.js"
import * as fiberRuntime from "./internal/fiberRuntime.js"
import type * as Option from "./Option.js"
import type * as order from "./Order.js"
import type { Pipeable } from "./Pipeable.js"
import type * as RuntimeFlags from "./RuntimeFlags.js"
import type { Scheduler } from "./Scheduler.js"
import type * as Scope from "./Scope.js"
import type { Supervisor } from "./Supervisor.js"
import type { AnySpan, Tracer } from "./Tracer.js"
import type * as Types from "./Types.js"
import type * as Unify from "./Unify.js"

/**
* @since 2.0.0
Expand Down Expand Up @@ -62,7 +62,7 @@ export type RuntimeFiberTypeId = typeof RuntimeFiberTypeId
* @since 2.0.0
* @category models
*/
export interface Fiber<out A, out E = never> extends Fiber.Variance<A, E>, Pipeable {
export interface Fiber<out A, out E = never> extends Effect.Effect<A, E>, Fiber.Variance<A, E> {
/**
* The identity of the fiber.
*/
Expand Down Expand Up @@ -97,6 +97,26 @@ export interface Fiber<out A, out E = never> extends Fiber.Variance<A, E>, Pipea
* resume immediately. Otherwise, the effect will resume when the fiber exits.
*/
interruptAsFork(fiberId: FiberId.FiberId): Effect.Effect<void>

readonly [Unify.typeSymbol]?: unknown
readonly [Unify.unifySymbol]?: FiberUnify<this>
readonly [Unify.ignoreSymbol]?: FiberUnifyIgnore
}

/**
* @category models
* @since 3.8.0
*/
export interface FiberUnify<A extends { [Unify.typeSymbol]?: any }> extends Effect.EffectUnify<A> {
Fiber?: () => A[Unify.typeSymbol] extends Fiber<infer A0, infer E0> | infer _ ? Fiber<A0, E0> : never
}

/**
* @category models
* @since 3.8.0
*/
export interface FiberUnifyIgnore extends Effect.EffectUnifyIgnore {
Effect?: true
}

/**
Expand Down Expand Up @@ -190,6 +210,27 @@ export interface RuntimeFiber<out A, out E = never> extends Fiber<A, E>, Fiber.R
* Gets the current supervisor
*/
get currentSupervisor(): Supervisor<unknown>

readonly [Unify.typeSymbol]?: unknown
readonly [Unify.unifySymbol]?: RuntimeFiberUnify<this>
readonly [Unify.ignoreSymbol]?: RuntimeFiberUnifyIgnore
}

/**
* @category models
* @since 3.8.0
*/
export interface RuntimeFiberUnify<A extends { [Unify.typeSymbol]?: any }> extends FiberUnify<A> {
RuntimeFiber?: () => A[Unify.typeSymbol] extends RuntimeFiber<infer A0, infer E0> | infer _ ? RuntimeFiber<A0, E0>
: never
}

/**
* @category models
* @since 3.8.0
*/
export interface RuntimeFiberUnifyIgnore extends FiberUnifyIgnore {
Fiber?: true
}

/**
Expand Down
4 changes: 4 additions & 0 deletions packages/effect/src/internal/effect/circular.ts
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,10 @@ export const zipWithFiber = dual<
f: (a: A, b: B) => C
) => Fiber.Fiber<C, E | E2>
>(3, (self, that, f) => ({
...Effectable.CommitPrototype,
commit() {
return internalFiber.join(this)
},
[internalFiber.FiberTypeId]: internalFiber.fiberVariance,
id: () => pipe(self.id(), FiberId.getOrElse(that.id())),
await: pipe(
Expand Down
85 changes: 56 additions & 29 deletions packages/effect/src/internal/fiber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import * as order from "../Order.js"
import { pipeArguments } from "../Pipeable.js"
import { hasProperty } from "../Predicate.js"
import * as core from "./core.js"
import * as effectable from "./effectable.js"
import * as fiberScope from "./fiberScope.js"
import * as runtimeFlags from "./runtimeFlags.js"

Expand Down Expand Up @@ -76,15 +77,23 @@ export const children = <A, E>(
): Effect.Effect<Array<Fiber.RuntimeFiber<any, any>>> => self.children

/** @internal */
export const done = <A, E>(exit: Exit.Exit<A, E>): Fiber.Fiber<A, E> => ({
...fiberProto,
id: () => FiberId.none,
await: core.succeed(exit),
children: core.succeed([]),
inheritAll: core.void,
poll: core.succeed(Option.some(exit)),
interruptAsFork: () => core.void
})
export const done = <A, E>(exit: Exit.Exit<A, E>): Fiber.Fiber<A, E> => {
const _fiber = {
...effectable.CommitPrototype,
commit() {
return join(this)
},
...fiberProto,
id: () => FiberId.none,
await: core.succeed(exit),
children: core.succeed([]),
inheritAll: core.void,
poll: core.succeed(Option.some(exit)),
interruptAsFork: () => core.void
}

return _fiber
}

/** @internal */
export const dump = <A, E>(self: Fiber.RuntimeFiber<A, E>): Effect.Effect<Fiber.Fiber.Dump> =>
Expand Down Expand Up @@ -148,25 +157,32 @@ export const map = dual<
export const mapEffect = dual<
<A, A2, E2>(f: (a: A) => Effect.Effect<A2, E2>) => <E>(self: Fiber.Fiber<A, E>) => Fiber.Fiber<A2, E | E2>,
<A, E, A2, E2>(self: Fiber.Fiber<A, E>, f: (a: A) => Effect.Effect<A2, E2>) => Fiber.Fiber<A2, E | E2>
>(2, (self, f) => ({
...fiberProto,
id: () => self.id(),
await: core.flatMap(self.await, Exit.forEachEffect(f)),
children: self.children,
inheritAll: self.inheritAll,
poll: core.flatMap(self.poll, (result) => {
switch (result._tag) {
case "None":
return core.succeed(Option.none())
case "Some":
return pipe(
Exit.forEachEffect(result.value, f),
core.map(Option.some)
)
}
}),
interruptAsFork: (id) => self.interruptAsFork(id)
}))
>(2, (self, f) => {
const _fiber = {
...effectable.CommitPrototype,
commit() {
return join(this)
},
...fiberProto,
id: () => self.id(),
await: core.flatMap(self.await, Exit.forEachEffect(f)),
children: self.children,
inheritAll: self.inheritAll,
poll: core.flatMap(self.poll, (result) => {
switch (result._tag) {
case "None":
return core.succeed(Option.none())
case "Some":
return pipe(
Exit.forEachEffect(result.value, f),
core.map(Option.some)
)
}
}),
interruptAsFork: (id: FiberId.FiberId) => self.interruptAsFork(id)
}
return _fiber
})

/** @internal */
export const mapFiber = dual<
Expand Down Expand Up @@ -212,7 +228,11 @@ export const match = dual<
})

/** @internal */
export const never: Fiber.Fiber<never> = {
const _never = {
...effectable.CommitPrototype,
commit() {
return join(this)
},
...fiberProto,
id: () => FiberId.none,
await: core.never,
Expand All @@ -222,11 +242,18 @@ export const never: Fiber.Fiber<never> = {
interruptAsFork: () => core.never
}

/** @internal */
export const never: Fiber.Fiber<never> = _never

/** @internal */
export const orElse = dual<
<A2, E2>(that: Fiber.Fiber<A2, E2>) => <A, E>(self: Fiber.Fiber<A, E>) => Fiber.Fiber<A | A2, E | E2>,
<A, E, A2, E2>(self: Fiber.Fiber<A, E>, that: Fiber.Fiber<A2, E2>) => Fiber.Fiber<A | A2, E | E2>
>(2, (self, that) => ({
...effectable.CommitPrototype,
commit() {
return join(this)
},
...fiberProto,
id: () => FiberId.getOrElse(self.id(), that.id()),
await: core.zipWith(
Expand Down
Loading

0 comments on commit d2e5807

Please sign in to comment.