Skip to content

Commit

Permalink
Micro.EnvRef and Micro.Handle is subtype of Micro (#3661)
Browse files Browse the repository at this point in the history
Co-authored-by: maksim.khramtsov <[email protected]>
Co-authored-by: Tim <[email protected]>
  • Loading branch information
3 people authored Sep 24, 2024
1 parent ad7e1de commit 4509656
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 49 deletions.
5 changes: 5 additions & 0 deletions .changeset/poor-keys-lick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": patch
---

`Micro.EnvRef` and `Micro.Handle` is subtype of `Micro`
8 changes: 8 additions & 0 deletions packages/effect/dtslint/Unify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ export type StreamUnify = Unify.Unify<
export type MicroUnify = Unify.Unify<
Micro.Micro<0, 1, 2> | Micro.Micro<"a", "b", "c">
>
// $ExpectType EnvRef<0 | "a">
export type MicroEnvRefUnify = Unify.Unify<
Micro.EnvRef<0> | Micro.EnvRef<"a">
>
// $ExpectType Handle<0 | "a", "b" | 1>
export type MicroHandleUnify = Unify.Unify<
Micro.Handle<0, 1> | Micro.Handle<"a", "b">
>
// $ExpectType Effect<0 | "a", "b" | 1, "c" | 2>
export type EffectUnify = Unify.Unify<
| Effect.Effect<0, 1, 2>
Expand Down
180 changes: 136 additions & 44 deletions packages/effect/src/Micro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ export type runSymbol = typeof runSymbol
*/
export interface Micro<out A, out E = never, out R = never> extends Effect<A, E, R> {
readonly [TypeId]: Micro.Variance<A, E, R>
readonly [runSymbol]: (env: Env<any>, onExit: (exit: MicroExit<A, E>) => void) => void
[runSymbol](env: Env<any>, onExit: (exit: MicroExit<A, E>) => void): void
[Symbol.iterator](): MicroIterator<Micro<A, E, R>>
[Unify.typeSymbol]?: unknown
[Unify.unifySymbol]?: MicroUnify<this>
[Unify.ignoreSymbol]?: MicroUnifyIgnore
[Symbol.iterator](): MicroIterator<Micro<A, E, R>>
}

/**
Expand Down Expand Up @@ -144,6 +144,58 @@ export interface MicroIterator<T extends Micro<any, any, any>> {
next(...args: ReadonlyArray<any>): IteratorResult<YieldWrap<T>, Micro.Success<T>>
}

/**
* @since 3.8.4
* @experimental
* @category models
*/
export interface MicroClass {
new<A, E = never, R = never>(): Micro<A, E, R>
}

// ----------------------------------------------------------------------------
// Microable
// ----------------------------------------------------------------------------

const MicroProto = {
...Effectable.EffectPrototype,
_op: "Micro",
[TypeId]: {
_A: identity,
_E: identity,
_R: identity
},
[Symbol.iterator]() {
return new SingleShotGen(new YieldWrap(this)) as any
}
}

const MicroBase: MicroClass = (function() {
function Base() {}
Base.prototype = MicroProto
return Base as any
})()

/**
* @since 3.8.4
* @experimental
* @category constructors
*/
export abstract class Class<out A, out E = never, out R = never> extends MicroBase<A, E, R> {
/**
* @since 3.8.4
* @experimental
*/
abstract asMicro(): Micro<A, E, R>
/**
* @since 3.8.4
* @experimental
*/
[runSymbol](env: Env<any>, onExit: (exit: MicroExit<A, E>) => void): void {
this.asMicro()[runSymbol](env, onExit)
}
}

// ----------------------------------------------------------------------------
// MicroCause
// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -512,31 +564,6 @@ export interface Env<R> extends Pipeable {
readonly refs: ReadonlyRecord<string, unknown>
}

/**
* @since 3.4.0
* @experimental
* @category environment
*/
export const EnvRefTypeId: unique symbol = Symbol.for("effect/Micro/EnvRef")

/**
* @since 3.4.0
* @experimental
* @category environment
*/
export type EnvRefTypeId = typeof EnvRefTypeId

/**
* @since 3.4.0
* @experimental
* @category environment
*/
export interface EnvRef<A> {
readonly [EnvRefTypeId]: EnvRefTypeId
readonly key: string
readonly initial: A
}

const EnvProto = {
[EnvTypeId]: {
_R: identity
Expand Down Expand Up @@ -818,8 +845,59 @@ export class MicroSchedulerDefault implements MicroScheduler {
// Env refs
// ========================================================================

const EnvRefProto = {
[EnvRefTypeId]: EnvRefTypeId
/**
* @since 3.4.0
* @experimental
* @category environment
*/
export const EnvRefTypeId: unique symbol = Symbol.for("effect/Micro/EnvRef")

/**
* @since 3.4.0
* @experimental
* @category environment
*/
export type EnvRefTypeId = typeof EnvRefTypeId

/**
* @since 3.4.0
* @experimental
* @category environment
*/
export interface EnvRef<A> extends Micro<A> {
readonly [EnvRefTypeId]: EnvRefTypeId
readonly key: string
readonly initial: A

[Unify.typeSymbol]?: unknown
[Unify.unifySymbol]?: EnvRefUnify<this>
[Unify.ignoreSymbol]?: EnvRefUnifyIgnore
}

/**
* @category models
* @since 3.8.4
* @experimental
*/
export interface EnvRefUnify<A extends { [Unify.typeSymbol]?: any }> extends MicroUnify<A> {
EnvRef?: () => A[Unify.typeSymbol] extends EnvRef<infer A0> | infer _ ? EnvRef<A0> : never
}

/**
* @category models
* @since 3.8.4
* @experimental
*/
export interface EnvRefUnifyIgnore extends MicroUnifyIgnore {
Micro?: true
}

const EnvRefProto: ThisType<EnvRef<any>> = {
...MicroProto,
[EnvRefTypeId]: EnvRefTypeId,
[runSymbol](env: Env<any>, onExit: (exit: MicroExit<any, any>) => void) {
getEnvRef(this)[runSymbol](env, onExit)
}
}

/**
Expand Down Expand Up @@ -929,19 +1007,6 @@ export const withConcurrency: {
// constructors
// ----------------------------------------------------------------------------

const MicroProto = {
...Effectable.EffectPrototype,
_op: "Micro",
[TypeId]: {
_A: identity,
_E: identity,
_R: identity
},
[Symbol.iterator]() {
return new SingleShotGen(new YieldWrap(this)) as any
}
}

const microDepthState = globalValue("effect/Micro/microDepthState", () => ({
depth: 0,
maxDepthBeforeYield: currentMaxDepthBeforeYield.initial
Expand Down Expand Up @@ -3652,7 +3717,7 @@ export type HandleTypeId = typeof HandleTypeId
* @experimental
* @category handle & forking
*/
export interface Handle<A, E = never> {
export interface Handle<A, E = never> extends Micro<A, E> {
readonly [HandleTypeId]: HandleTypeId
readonly await: Micro<MicroExit<A, E>>
readonly join: Micro<A, E>
Expand All @@ -3661,6 +3726,28 @@ export interface Handle<A, E = never> {
readonly addObserver: (observer: (exit: MicroExit<A, E>) => void) => void
readonly removeObserver: (observer: (exit: MicroExit<A, E>) => void) => void
readonly unsafePoll: () => MicroExit<A, E> | null

[Unify.typeSymbol]?: unknown
[Unify.unifySymbol]?: HandleUnify<this>
[Unify.ignoreSymbol]?: HandleUnifyIgnore
}

/**
* @category models
* @since 3.8.4
* @experimental
*/
export interface HandleUnify<A extends { [Unify.typeSymbol]?: any }> extends MicroUnify<A> {
Handle?: () => A[Unify.typeSymbol] extends Handle<infer A0, infer E0> | infer _ ? Handle<A0, E0> : never
}

/**
* @category models
* @since 3.8.4
* @experimental
*/
export interface HandleUnifyIgnore extends MicroUnifyIgnore {
Micro?: true
}

/**
Expand All @@ -3671,7 +3758,7 @@ export interface Handle<A, E = never> {
export const isHandle = (u: unknown): u is Handle<unknown, unknown> =>
typeof u === "object" && u !== null && HandleTypeId in u

class HandleImpl<A, E> implements Handle<A, E> {
class HandleImpl<A, E> extends Class<A, E> implements Handle<A, E> {
readonly [HandleTypeId]: HandleTypeId

readonly observers: Set<(exit: MicroExit<A, E>) => void> = new Set()
Expand All @@ -3680,6 +3767,7 @@ class HandleImpl<A, E> implements Handle<A, E> {
readonly isRoot: boolean

constructor(readonly parentSignal: AbortSignal, controller?: AbortController) {
super()
this[HandleTypeId] = HandleTypeId
this.isRoot = controller !== undefined
this._controller = controller ?? new AbortController()
Expand Down Expand Up @@ -3746,6 +3834,10 @@ class HandleImpl<A, E> implements Handle<A, E> {
return this.await
})
}

asMicro(): Micro<A, E> {
return this.join
}
}

/**
Expand Down
35 changes: 30 additions & 5 deletions packages/effect/test/Micro.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ describe.concurrent("Micro", () => {
it.effect("raceAll", () =>
Micro.gen(function*() {
const interrupted: Array<number> = []
const result = yield* Micro.raceAll([100, 75, 50, 0, 25].map((ms) =>
const result = yield* Micro.raceAll([500, 300, 200, 0, 100].map((ms) =>
(ms === 0 ? Micro.fail("boom") : Micro.succeed(ms)).pipe(
Micro.delay(ms),
Micro.onInterrupt(
Expand All @@ -341,14 +341,14 @@ describe.concurrent("Micro", () => {
)
)
))
assert.strictEqual(result, 25)
assert.deepStrictEqual(interrupted, [100, 75, 50])
assert.strictEqual(result, 100)
assert.deepStrictEqual(interrupted, [500, 300, 200])
}))

it("raceAllFirst", () =>
Micro.gen(function*() {
const interrupted: Array<number> = []
const result = yield* Micro.raceAllFirst([100, 75, 50, 0, 25].map((ms) =>
const result = yield* Micro.raceAllFirst([500, 300, 200, 0, 100].map((ms) =>
(ms === 0 ? Micro.fail("boom") : Micro.succeed(ms)).pipe(
Micro.delay(ms),
Micro.onInterrupt(
Expand All @@ -359,7 +359,7 @@ describe.concurrent("Micro", () => {
)
)).pipe(Micro.exit)
assert.deepStrictEqual(result, Micro.exitFail("boom"))
assert.deepStrictEqual(interrupted, [100, 75, 50, 25])
assert.deepStrictEqual(interrupted, [500, 300, 200, 100])
}).pipe(Micro.runPromise))

describe("valid Effect", () => {
Expand Down Expand Up @@ -1193,4 +1193,29 @@ describe.concurrent("Micro", () => {
assert.deepStrictEqual(out, [100, 100, 100, 160, 320, 640, 1280])
})
})

describe("Handle", () => {
it("is subtype of Micro: (Success)", () =>
Micro.gen(function*() {
const handle = yield* Micro.succeed(1).pipe(Micro.fork)
const res = yield* handle
assert.equal(res, 1)
}).pipe(Micro.runPromise))

it("is subtype of Micro: (Failure)", () =>
Micro.gen(function*() {
const handle = yield* Micro.fail(1).pipe(Micro.fork)
const res = yield* Micro.flip(handle)
assert.equal(res, 1)
}).pipe(Micro.runPromise))
})

describe("EnvRef", () => {
it("is subtype of Micro", () =>
Micro.gen(function*() {
const envRef = Micro.envRefMake("test", () => 1)
const res = yield* envRef
assert.equal(res, 1)
}).pipe(Micro.runPromise))
})
})

0 comments on commit 4509656

Please sign in to comment.