@@ -1,4 +1,4 @@
|
|||||||
import { Effect, Pipeable, Predicate, Readable, Stream, Subscribable, SubscriptionRef } from "effect"
|
import { Effect, Pipeable, Predicate, Readable, Stream, Subscribable, type SubscriptionRef } from "effect"
|
||||||
|
|
||||||
|
|
||||||
export const LensTypeId: unique symbol = Symbol.for("@effect-fc/Lens/Lens")
|
export const LensTypeId: unique symbol = Symbol.for("@effect-fc/Lens/Lens")
|
||||||
@@ -8,7 +8,6 @@ export interface Lens<in out A, in out ER = never, in out RR = never, in out EW
|
|||||||
extends Subscribable.Subscribable<A, ER, RR> {
|
extends Subscribable.Subscribable<A, ER, RR> {
|
||||||
readonly [LensTypeId]: LensTypeId
|
readonly [LensTypeId]: LensTypeId
|
||||||
|
|
||||||
readonly set: (a: A) => Effect.Effect<void, EW, RW>
|
|
||||||
readonly modify: <B, E1 = never, R1 = never>(
|
readonly modify: <B, E1 = never, R1 = never>(
|
||||||
f: (a: A) => Effect.Effect<readonly [B, A], E1, R1>
|
f: (a: A) => Effect.Effect<readonly [B, A], E1, R1>
|
||||||
) => Effect.Effect<B, ER | EW | E1, RR | RW | R1>
|
) => Effect.Effect<B, ER | EW | E1, RR | RW | R1>
|
||||||
@@ -23,30 +22,42 @@ extends Pipeable.Class() implements Lens<A, ER, RR, EW, RW> {
|
|||||||
constructor(
|
constructor(
|
||||||
readonly get: Effect.Effect<A, ER, RR>,
|
readonly get: Effect.Effect<A, ER, RR>,
|
||||||
readonly changes: Stream.Stream<A, ER, RR>,
|
readonly changes: Stream.Stream<A, ER, RR>,
|
||||||
readonly set: (a: A) => Effect.Effect<void, EW, RW>,
|
readonly modify: <B, E1 = never, R1 = never>(
|
||||||
|
f: (a: A) => Effect.Effect<readonly [B, A], E1, R1>
|
||||||
|
) => Effect.Effect<B, ER | EW | E1, RR | RW | R1>,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
modify<B, E1 = never, R1 = never>(
|
|
||||||
f: (a: A) => Effect.Effect<readonly [B, A], E1, R1>
|
|
||||||
) {
|
|
||||||
return Effect.flatMap(
|
|
||||||
this.get,
|
|
||||||
a => Effect.flatMap(f(a), ([b, next]) => Effect.as(this.set(next), b)
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const isLens = (u: unknown): u is Lens<unknown, unknown, unknown, unknown, unknown> => Predicate.hasProperty(u, LensTypeId)
|
export const isLens = (u: unknown): u is Lens<unknown, unknown, unknown, unknown, unknown> => Predicate.hasProperty(u, LensTypeId)
|
||||||
|
|
||||||
|
|
||||||
export const make = <A, ER, RR, EW, RW>(options: {
|
export const make = <A, ER, RR, EW, RW>(
|
||||||
readonly get: Effect.Effect<A, ER, RR>
|
options: {
|
||||||
readonly changes: Stream.Stream<A, ER, RR>
|
readonly get: Effect.Effect<A, ER, RR>
|
||||||
readonly set: (a: A) => Effect.Effect<void, EW, RW>
|
readonly changes: Stream.Stream<A, ER, RR>
|
||||||
}): Lens<A, ER, RR, EW, RW> => new LensImpl(options.get, options.changes, options.set)
|
} & (
|
||||||
|
| {
|
||||||
|
readonly modify: <B, E1 = never, R1 = never>(
|
||||||
|
f: (a: A) => Effect.Effect<readonly [B, A], E1, R1>
|
||||||
|
) => Effect.Effect<B, ER | EW | E1, RR | RW | R1>
|
||||||
|
}
|
||||||
|
| { readonly set: (a: A) => Effect.Effect<void, EW, RW> }
|
||||||
|
)
|
||||||
|
): Lens<A, ER, RR, EW, RW> => new LensImpl<A, ER, RR, EW, RW>(
|
||||||
|
options.get,
|
||||||
|
options.changes,
|
||||||
|
Predicate.hasProperty(options, "modify")
|
||||||
|
? options.modify
|
||||||
|
: <B, E1 = never, R1 = never>(
|
||||||
|
f: (a: A) => Effect.Effect<readonly [B, A], E1, R1>
|
||||||
|
) => Effect.flatMap(
|
||||||
|
options.get,
|
||||||
|
a => Effect.flatMap(f(a), ([b, next]) => Effect.as(options.set(next), b)
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a `Lens` that directly proxies a `SubscriptionRef`.
|
* Creates a `Lens` that directly proxies a `SubscriptionRef`.
|
||||||
@@ -56,52 +67,47 @@ export const fromSubscriptionRef = <A>(
|
|||||||
): Lens<A, never, never, never, never> => make({
|
): Lens<A, never, never, never, never> => make({
|
||||||
get: ref.get,
|
get: ref.get,
|
||||||
get changes() { return ref.changes },
|
get changes() { return ref.changes },
|
||||||
set: a => SubscriptionRef.set(ref, a),
|
modify: ref.modifyEffect,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
export const map = <A, ER, RR, EW, RW, B>(
|
export const map = <A, ER, RR, EW, RW, B>(
|
||||||
self: Lens<A, ER, RR, EW, RW>,
|
self: Lens<A, ER, RR, EW, RW>,
|
||||||
get: (a: A) => B,
|
get: (a: A) => B,
|
||||||
set: (b: B) => A,
|
set: (b: B, parent: A) => A,
|
||||||
): Lens<B, ER, RR, EW, RW> => {
|
): Lens<B, ER, RR, EW, RW> => {
|
||||||
make({
|
const getEffect = Effect.map(self.get, get)
|
||||||
get: Effect.map(self.get, get),
|
const changes = Stream.map(self.changes, get)
|
||||||
changes: Stream.map(self.changes, get),
|
const modify = <C, E1 = never, R1 = never>(
|
||||||
|
|
||||||
})
|
|
||||||
const get = Effect.map(self.get, f)
|
|
||||||
const changes = Stream.map(self.changes, f)
|
|
||||||
const set = (b: B) => self.set(g(b))
|
|
||||||
|
|
||||||
const out = new LensImpl(get, changes, set)
|
|
||||||
|
|
||||||
;(out as any).modify = <C, E1 = never, R1 = never>(
|
|
||||||
h: (b: B) => Effect.Effect<readonly [C, B], E1, R1>
|
h: (b: B) => Effect.Effect<readonly [C, B], E1, R1>
|
||||||
) => self.modify((a: A) => {
|
) => self.modify((a: A) => {
|
||||||
const b = f(a)
|
const b = get(a)
|
||||||
return Effect.flatMap(h(b), ([c, bNext]) => Effect.succeed([c, g(bNext)] as const))
|
return Effect.flatMap(h(b), ([c, bNext]) => Effect.succeed([c, set(bNext, a)] as const))
|
||||||
})
|
})
|
||||||
|
|
||||||
return out
|
return make({
|
||||||
|
get: getEffect,
|
||||||
|
changes,
|
||||||
|
modify,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mapEffect = <A, ER, RR, EW, RW, B, EGet = never, RGet = never, ESet = never, RSet = never>(
|
export const mapEffect = <A, ER, RR, EW, RW, B, EGet = never, RGet = never, ESet = never, RSet = never>(
|
||||||
self: Lens<A, ER, RR, EW, RW>,
|
self: Lens<A, ER, RR, EW, RW>,
|
||||||
getF: (a: A) => Effect.Effect<B, EGet, RGet>,
|
getF: (a: A) => Effect.Effect<B, EGet, RGet>,
|
||||||
setF: (b: B) => Effect.Effect<A, ESet, RSet>,
|
setF: (b: B, parent: A) => Effect.Effect<A, ESet, RSet>,
|
||||||
): Lens<B, ER | EGet, RR | RGet, EW | ESet, RW | RSet> => {
|
): Lens<B, ER | EGet, RR | RGet, EW | ESet, RW | RSet> => {
|
||||||
const get = Effect.flatMap(self.get, getF)
|
const get = Effect.flatMap(self.get, getF)
|
||||||
const changes = Stream.mapEffect(self.changes, getF)
|
const changes = Stream.mapEffect(self.changes, getF)
|
||||||
const set = (b: B) => Effect.flatMap(setF(b), a => self.set(a))
|
const modify = <C, E1 = never, R1 = never>(
|
||||||
|
|
||||||
const out = new LensImpl(get, changes, set)
|
|
||||||
|
|
||||||
;(out as any).modify = <C, E1 = never, R1 = never>(
|
|
||||||
h: (b: B) => Effect.Effect<readonly [C, B], E1, R1>
|
h: (b: B) => Effect.Effect<readonly [C, B], E1, R1>
|
||||||
) => self.modify((a: A) => Effect.flatMap(getF(a), b => Effect.flatMap(h(b), ([c, bNext]) => Effect.flatMap(setF(bNext), nextA => Effect.succeed([c, nextA] as const)))))
|
) => self.modify((a: A) => Effect.flatMap(getF(a), b => Effect.flatMap(h(b), ([c, bNext]) => Effect.flatMap(setF(bNext, a), nextA => Effect.succeed([c, nextA] as const)))))
|
||||||
|
|
||||||
return out
|
return make({
|
||||||
|
get,
|
||||||
|
changes,
|
||||||
|
modify,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const unwrap = <A, ER, RR, EW, RW, E1, R1>(
|
export const unwrap = <A, ER, RR, EW, RW, E1, R1>(
|
||||||
@@ -109,5 +115,7 @@ export const unwrap = <A, ER, RR, EW, RW, E1, R1>(
|
|||||||
): Lens<A, ER | E1, RR | R1, EW | E1, RW | R1> => make({
|
): Lens<A, ER | E1, RR | R1, EW | E1, RW | R1> => make({
|
||||||
get: Effect.flatMap(effect, l => l.get),
|
get: Effect.flatMap(effect, l => l.get),
|
||||||
changes: Stream.unwrap(Effect.map(effect, l => l.changes)),
|
changes: Stream.unwrap(Effect.map(effect, l => l.changes)),
|
||||||
set: a => Effect.flatMap(effect, l => l.set(a)),
|
modify: <B, E2 = never, R2 = never>(
|
||||||
|
f: (a: A) => Effect.Effect<readonly [B, A], E2, R2>
|
||||||
|
) => Effect.flatMap(effect, l => l.modify(f)),
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user