Skip to content

Commit

Permalink
Made Ref, SynchronizedRef,RcRef, and SubscriptionRef` a subtype…
Browse files Browse the repository at this point in the history
… of `Effect` (#3511)

Co-authored-by: maksim.khramtsov <[email protected]>
  • Loading branch information
2 people authored and gcanti committed Sep 10, 2024
1 parent 356ab38 commit 6acc129
Show file tree
Hide file tree
Showing 13 changed files with 195 additions and 54 deletions.
5 changes: 5 additions & 0 deletions .changeset/eighty-lobsters-refuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": minor
---

Made `Ref`, `SynchronizedRed` and `SubscriptionRef` a subtype of `Effect`
61 changes: 54 additions & 7 deletions packages/effect/dtslint/Unify.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import type * as Effect from "effect/Effect"
import * as Either from "effect/Either"
import type * as Exit from "effect/Exit"
import type * as Micro from "effect/Micro"
import type * as Option from "effect/Option"
import type * as RcRef from "effect/RcRef"
import type * as Ref from "effect/Ref"
import type * as Stream from "effect/Stream"
import type * as SubscriptionRef from "effect/SubscriptionRef"
import type * as SynchronizedRef from "effect/SynchronizedRef"
import * as Unify from "effect/Unify"

// $ExpectType Option<string | number>
export type option = Unify.Unify<Option.Option<number> | Option.Option<string>>
export type OptionUnify = Unify.Unify<Option.Option<number> | Option.Option<string>>

// $ExpectType Either<"RA" | "RB", "LA" | "LB">
export type either = Unify.Unify<Either.Either<"RA", "LA"> | Either.Either<"RB", "LB">>
export type EitherUnify = Unify.Unify<Either.Either<"RA", "LA"> | Either.Either<"RB", "LB">>

// $ExpectType 0 | Option<string | number> | Either<"RA" | "RB", "LA" | "LB">
export type both = Unify.Unify<
export type EitherOptionUnify = Unify.Unify<
Either.Either<"RA", "LA"> | Either.Either<"RB", "LB"> | Option.Option<number> | Option.Option<string> | 0
>

Expand All @@ -26,15 +31,57 @@ Unify.unify(<N>(n: N) => Math.random() > 0 ? Either.right(n) : Either.left("ok")
Unify.unify(Math.random() > 0 ? Either.right(10) : Either.left("ok"))

// $ExpectType Stream<0 | "a", "b" | 1, "c" | 2>
export type SU = Unify.Unify<
export type StreamUnify = Unify.Unify<
Stream.Stream<0, 1, 2> | Stream.Stream<"a", "b", "c">
>

// $ExpectType Micro<0 | "a", "b" | 1, "c" | 2>
export type MU = Unify.Unify<
export type MicroUnify = Unify.Unify<
Micro.Micro<0, 1, 2> | Micro.Micro<"a", "b", "c">
>
// $ExpectType Effect<0 | "a", "b" | 1, "c" | 2>
export type EU = Unify.Unify<
Effect.Effect<0, 1, 2> | Effect.Effect<"a", "b", "c">
export type EffectUnify = Unify.Unify<
| Effect.Effect<0, 1, 2>
| Effect.Effect<"a", "b", "c">
>
// $ExpectType Exit<0 | "a", "b" | 1>
export type ExitUnify = Unify.Unify<
| Exit.Exit<0, 1>
| Exit.Exit<"a", "b">
>
// $ExpectType Ref<1> | Ref<"a">
export type RefUnify = Unify.Unify<Ref.Ref<1> | Ref.Ref<"a">>
// $ExpectType SynchronizedRef<1> | SynchronizedRef<"a">
export type SynchronizedRefUnify = Unify.Unify<
| SynchronizedRef.SynchronizedRef<1>
| SynchronizedRef.SynchronizedRef<"a">
>
// $ExpectType SubscriptionRef<1> | SubscriptionRef<"a">
export type SubscriptionRefUnify = Unify.Unify<
| SubscriptionRef.SubscriptionRef<1>
| SubscriptionRef.SubscriptionRef<"a">
>
// $ExpectType RcRef<"a" | 1, "b" | 2>
export type RcRefUnify = Unify.Unify<
| RcRef.RcRef<1, 2>
| RcRef.RcRef<"a", "b">
>

// $ExpectType 0 | Option<string | number> | Ref<1> | SynchronizedRef<1> | SubscriptionRef<1> | Ref<"A"> | SynchronizedRef<"A"> | SubscriptionRef<"A"> | 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">
| Option.Option<number>
| Option.Option<string>
| Effect.Effect<"A", "E", "R">
| Effect.Effect<1, 0, "R1">
| Ref.Ref<1>
| Ref.Ref<"A">
| SynchronizedRef.SynchronizedRef<1>
| SynchronizedRef.SynchronizedRef<"A">
| SubscriptionRef.SubscriptionRef<1>
| SubscriptionRef.SubscriptionRef<"A">
| RcRef.RcRef<1, 0>
| RcRef.RcRef<"A", "E">
| 0
>
26 changes: 24 additions & 2 deletions packages/effect/src/RcRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
import type * as Duration from "./Duration.js"
import type * as Effect from "./Effect.js"
import * as internal from "./internal/rcRef.js"
import { type Pipeable } from "./Pipeable.js"
import type * as Readable from "./Readable.js"
import type * as Scope from "./Scope.js"
import type * as Types from "./Types.js"
import type * as Unify from "./Unify.js"

/**
* @since 3.5.0
Expand All @@ -24,10 +25,31 @@ export type TypeId = typeof TypeId
* @since 3.5.0
* @category models
*/
export interface RcRef<out A, out E = never> extends Pipeable {
export interface RcRef<out A, out E = never>
extends Effect.Effect<A, E, Scope.Scope>, Readable.Readable<A, E, Scope.Scope>
{
readonly [TypeId]: RcRef.Variance<A, E>
readonly [Unify.typeSymbol]?: unknown
readonly [Unify.unifySymbol]?: RcRefUnify<this>
readonly [Unify.ignoreSymbol]?: RcRefUnifyIgnore
}

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

/**
* @category models
* @since 3.8.0
*/
export interface RcRefUnifyIgnore extends Effect.EffectUnifyIgnore {
Effect?: true
}
/**
* @since 3.5.0
* @category models
Expand Down
24 changes: 22 additions & 2 deletions packages/effect/src/Ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import type * as Effect from "./Effect.js"
import * as internal from "./internal/ref.js"
import type * as Option from "./Option.js"
import type { Readable } from "./Readable.js"
import type * as Readable from "./Readable.js"
import type * as Types from "./Types.js"
import type * as Unify from "./Unify.js"

/**
* @since 2.0.0
Expand All @@ -23,8 +24,27 @@ export type RefTypeId = typeof RefTypeId
* @since 2.0.0
* @category models
*/
export interface Ref<in out A> extends Ref.Variance<A>, Readable<A> {
export interface Ref<in out A> extends Ref.Variance<A>, Effect.Effect<A>, Readable.Readable<A> {
modify<B>(f: (a: A) => readonly [B, A]): Effect.Effect<B>
readonly [Unify.typeSymbol]?: unknown
readonly [Unify.unifySymbol]?: RefUnify<this>
readonly [Unify.ignoreSymbol]?: RefUnifyIgnore
}

/**
* @category models
* @since 3.8.0
*/
export interface RefUnify<A extends { [Unify.typeSymbol]?: any }> extends Effect.EffectUnify<A> {
Ref?: () => Extract<A[Unify.typeSymbol], Ref<any>>
}

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

/**
Expand Down
22 changes: 22 additions & 0 deletions packages/effect/src/SubscriptionRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type * as Stream from "./Stream.js"
import type { Subscribable } from "./Subscribable.js"
import * as Synchronized from "./SynchronizedRef.js"
import type * as Types from "./Types.js"
import type * as Unify from "./Unify.js"

/**
* @since 2.0.0
Expand Down Expand Up @@ -44,6 +45,27 @@ export interface SubscriptionRef<in out A>
* to that value.
*/
readonly changes: Stream.Stream<A>
readonly [Unify.typeSymbol]?: unknown
readonly [Unify.unifySymbol]?: SubscriptionRefUnify<this>
readonly [Unify.ignoreSymbol]?: SubscriptionRefUnifyIgnore
}

/**
* @category models
* @since 3.8.0
*/
export interface SubscriptionRefUnify<A extends { [Unify.typeSymbol]?: any }>
extends Synchronized.SynchronizedRefUnify<A>
{
SubscriptionRef?: () => Extract<A[Unify.typeSymbol], SubscriptionRef<any>>
}

/**
* @category models
* @since 3.8.0
*/
export interface SubscriptionRefUnifyIgnore extends Synchronized.SynchronizedRefUnifyIgnore {
SynchronizedRef?: true
}

/**
Expand Down
20 changes: 20 additions & 0 deletions packages/effect/src/SynchronizedRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as internal from "./internal/synchronizedRef.js"
import type * as Option from "./Option.js"
import type * as Ref from "./Ref.js"
import type * as Types from "./Types.js"
import type * as Unify from "./Unify.js"

/**
* @since 2.0.0
Expand All @@ -27,6 +28,25 @@ export type SynchronizedRefTypeId = typeof SynchronizedRefTypeId
*/
export interface SynchronizedRef<in out A> extends SynchronizedRef.Variance<A>, Ref.Ref<A> {
modifyEffect<B, E, R>(f: (a: A) => Effect.Effect<readonly [B, A], E, R>): Effect.Effect<B, E, R>
readonly [Unify.typeSymbol]?: unknown
readonly [Unify.unifySymbol]?: SynchronizedRefUnify<this>
readonly [Unify.ignoreSymbol]?: SynchronizedRefUnifyIgnore
}

/**
* @category models
* @since 3.8.0
*/
export interface SynchronizedRefUnify<A extends { [Unify.typeSymbol]?: any }> extends Ref.RefUnify<A> {
SynchronizedRef?: () => Extract<A[Unify.typeSymbol], SynchronizedRef<any>>
}

/**
* @category models
* @since 3.8.0
*/
export interface SynchronizedRefUnifyIgnore extends Ref.RefUnifyIgnore {
Ref?: true
}

/**
Expand Down
13 changes: 7 additions & 6 deletions packages/effect/src/internal/effect/circular.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type * as Cause from "../../Cause.js"
import type * as Deferred from "../../Deferred.js"
import * as Duration from "../../Duration.js"
import type * as Effect from "../../Effect.js"
import * as Effectable from "../../Effectable.js"
import * as Equal from "../../Equal.js"
import type { Equivalence } from "../../Equivalence.js"
import * as Exit from "../../Exit.js"
Expand Down Expand Up @@ -571,18 +572,21 @@ export const synchronizedVariance = {
}

/** @internal */
class SynchronizedImpl<in out A> implements Synchronized.SynchronizedRef<A> {
class SynchronizedImpl<in out A> extends Effectable.Class<A> implements Synchronized.SynchronizedRef<A> {
readonly [SynchronizedTypeId] = synchronizedVariance
readonly [internalRef.RefTypeId] = internalRef.refVariance
readonly [Readable.TypeId]: Readable.TypeId
readonly [Readable.TypeId]: Readable.TypeId = Readable.TypeId
constructor(
readonly ref: Ref.Ref<A>,
readonly withLock: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
) {
this[Readable.TypeId] = Readable.TypeId
super()
this.get = internalRef.get(this.ref)
}
readonly get: Effect.Effect<A>
commit() {
return this.get
}
modify<B>(f: (a: A) => readonly [B, A]): Effect.Effect<B> {
return this.modifyEffect((a) => core.succeed(f(a)))
}
Expand All @@ -594,9 +598,6 @@ class SynchronizedImpl<in out A> implements Synchronized.SynchronizedRef<A> {
)
)
}
pipe() {
return pipeArguments(this, arguments)
}
}

/** @internal */
Expand Down
16 changes: 10 additions & 6 deletions packages/effect/src/internal/rcRef.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as Context from "../Context.js"
import * as Duration from "../Duration.js"
import type { Effect } from "../Effect.js"
import * as Effectable from "../Effectable.js"
import type { RuntimeFiber } from "../Fiber.js"
import { identity } from "../Function.js"
import { pipeArguments } from "../Pipeable.js"
import type * as RcRef from "../RcRef.js"
import * as Readable from "../Readable.js"
import type * as Scope from "../Scope.js"
import * as coreEffect from "./core-effect.js"
import * as core from "./core.js"
Expand Down Expand Up @@ -42,8 +43,9 @@ const variance: RcRef.RcRef.Variance<any, any> = {
_E: identity
}

class RcRefImpl<A, E> implements RcRef.RcRef<A, E> {
readonly [TypeId]: RcRef.RcRef.Variance<A, E>
class RcRefImpl<A, E> extends Effectable.Class<A, E, Scope.Scope> implements RcRef.RcRef<A, E> {
readonly [TypeId]: RcRef.RcRef.Variance<A, E> = variance
readonly [Readable.TypeId]: Readable.TypeId = Readable.TypeId

state: State<A> = stateEmpty
readonly semaphore = circular.unsafeMakeSemaphore(1)
Expand All @@ -54,11 +56,13 @@ class RcRefImpl<A, E> implements RcRef.RcRef<A, E> {
readonly scope: Scope.Scope,
readonly idleTimeToLive: Duration.Duration | undefined
) {
this[TypeId] = variance
super()
this.get = get(this)
}
readonly get: Effect<A, E, Scope.Scope>

pipe() {
return pipeArguments(this, arguments)
commit() {
return this.get
}
}

Expand Down
14 changes: 7 additions & 7 deletions packages/effect/src/internal/ref.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type * as Effect from "../Effect.js"
import * as Effectable from "../Effectable.js"
import { dual } from "../Function.js"
import * as MutableRef from "../MutableRef.js"
import * as Option from "../Option.js"
import { pipeArguments } from "../Pipeable.js"
import * as Readable from "../Readable.js"
import type * as Ref from "../Ref.js"
import * as core from "./core.js"
Expand All @@ -16,11 +16,14 @@ export const refVariance = {
_A: (_: any) => _
}

class RefImpl<in out A> implements Ref.Ref<A> {
class RefImpl<in out A> extends Effectable.Class<A> implements Ref.Ref<A> {
commit() {
return this.get
}
readonly [RefTypeId] = refVariance
readonly [Readable.TypeId]: Readable.TypeId
readonly [Readable.TypeId]: Readable.TypeId = Readable.TypeId
constructor(readonly ref: MutableRef.MutableRef<A>) {
this[Readable.TypeId] = Readable.TypeId
super()
this.get = core.sync(() => MutableRef.get(this.ref))
}
readonly get: Effect.Effect<A>
Expand All @@ -34,9 +37,6 @@ class RefImpl<in out A> implements Ref.Ref<A> {
return b
})
}
pipe() {
return pipeArguments(this, arguments)
}
}

/** @internal */
Expand Down
Loading

0 comments on commit 6acc129

Please sign in to comment.