This commit is contained in:
@@ -1,112 +1,38 @@
|
|||||||
import { Effect, Function, Pipeable, Predicate, Readable } from "effect"
|
import { Effect, Pipeable, Predicate } from "effect"
|
||||||
import type { NoInfer } from "effect/Types"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
export const WritableTypeId: unique symbol = Symbol.for("@effect-fc/Writable/Writable")
|
||||||
* @category type ids
|
export type WritableTypeId = typeof WritableTypeId
|
||||||
*/
|
|
||||||
export const TypeId: unique symbol = Symbol.for("@effect-fc/Writable")
|
|
||||||
|
|
||||||
/**
|
export interface Writable<in out A, E = never, R = never> extends WritablePrototype {
|
||||||
* @category type ids
|
readonly modify: <B>(f: (a: A) => readonly [B, A]) => Effect.Effect<B, E, R>
|
||||||
*/
|
|
||||||
export type TypeId = typeof TypeId
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a value that can be written to.
|
|
||||||
*
|
|
||||||
* Dual to `Readable`, which represents a value that can be read.
|
|
||||||
* A `Writable<A, E, R>` exposes a `set` operation that accepts a value of type
|
|
||||||
* `A` and returns an `Effect<void, E, R>`.
|
|
||||||
*
|
|
||||||
* @category models
|
|
||||||
*/
|
|
||||||
export interface Writable<in A, E = never, R = never> extends Pipeable.Pipeable {
|
|
||||||
readonly [TypeId]: TypeId
|
|
||||||
readonly set: (value: A) => Effect.Effect<void, E, R>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A `ReadWritable` is both `Readable` and `Writable` — it can be both read
|
|
||||||
* from and written to.
|
|
||||||
*
|
|
||||||
* @category models
|
|
||||||
*/
|
|
||||||
export interface ReadWritable<in out A, E = never, R = never>
|
|
||||||
extends Readable.Readable<A, E, R>, Writable<A, E, R> {}
|
|
||||||
|
|
||||||
/**
|
export interface WritablePrototype extends Pipeable.Pipeable {
|
||||||
* @category refinements
|
readonly [WritableTypeId]: WritableTypeId
|
||||||
*/
|
|
||||||
export const isWritable = (u: unknown): u is Writable<unknown, unknown, unknown> =>
|
|
||||||
Predicate.hasProperty(u, TypeId)
|
|
||||||
|
|
||||||
const Proto: Pick<Writable<unknown, unknown, unknown>, typeof TypeId | "pipe"> = {
|
|
||||||
[TypeId]: TypeId,
|
|
||||||
pipe(...args: Array<unknown>) {
|
|
||||||
return Pipeable.pipeArguments(this, args as any)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export const WritablePrototype: WritablePrototype = Object.freeze({
|
||||||
* Construct a `Writable` from a `set` function.
|
[WritableTypeId]: WritableTypeId,
|
||||||
*
|
...Pipeable.Prototype,
|
||||||
* @category constructors
|
} as const)
|
||||||
*/
|
|
||||||
export const make = <A, E, R>(set: (value: A) => Effect.Effect<void, E, R>): Writable<A, E, R> => {
|
|
||||||
const self = Object.create(Proto) as Writable<A, E, R>
|
export const isWritable = (u: unknown): u is Writable<unknown, unknown, unknown> => Predicate.hasProperty(u, WritableTypeId)
|
||||||
;(self as any).set = set
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a `ReadWritable` from a `get` effect and a `set` function.
|
* Construct a `Writable` from a `modify` function.
|
||||||
*
|
|
||||||
* @category constructors
|
|
||||||
*/
|
*/
|
||||||
export const makeReadWritable = <A, E, R>(options: {
|
export const make = <A, E, R>(
|
||||||
readonly get: Effect.Effect<A, E, R>
|
modify: <B>(f: (a: A) => readonly [B, A]) => Effect.Effect<B, E, R>,
|
||||||
readonly set: (value: A) => Effect.Effect<void, E, R>
|
): Writable<A, E, R> => Object.setPrototypeOf({ modify }, WritablePrototype)
|
||||||
}): ReadWritable<A, E, R> => {
|
|
||||||
const self = Object.create(Proto) as ReadWritable<A, E, R>
|
|
||||||
;(self as any).get = options.get
|
|
||||||
;(self as any).set = options.set
|
|
||||||
;(self as any)[Readable.TypeId] = Readable.TypeId
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform the input of a `Writable` using a pure function.
|
|
||||||
* The resulting `Writable` accepts values of type `B`, maps them to `A` with
|
|
||||||
* `f`, and then forwards them to the original `set`.
|
|
||||||
*
|
|
||||||
* @category combinators
|
|
||||||
*/
|
|
||||||
export const contramap: {
|
|
||||||
<B, A>(f: (b: NoInfer<B>) => A): <E, R>(self: Writable<A, E, R>) => Writable<B, E, R>
|
|
||||||
<A, E, R, B>(self: Writable<A, E, R>, f: (b: NoInfer<B>) => A): Writable<B, E, R>
|
|
||||||
} = Function.dual(2, <A, E, R, B>(self: Writable<A, E, R>, f: (b: B) => A): Writable<B, E, R> =>
|
|
||||||
make((b: B) => self.set(f(b)))
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform the input of a `Writable` using an effectful function.
|
|
||||||
*
|
|
||||||
* @category combinators
|
|
||||||
*/
|
|
||||||
export const contramapEffect: {
|
|
||||||
<B, A, E2, R2>(f: (b: NoInfer<B>) => Effect.Effect<A, E2, R2>): <E, R>(self: Writable<A, E, R>) => Writable<B, E | E2, R | R2>
|
|
||||||
<A, E, R, B, E2, R2>(self: Writable<A, E, R>, f: (b: NoInfer<B>) => Effect.Effect<A, E2, R2>): Writable<B, E | E2, R | R2>
|
|
||||||
} = Function.dual(2, <A, E, R, B, E2, R2>(self: Writable<A, E, R>, f: (b: B) => Effect.Effect<A, E2, R2>): Writable<B, E | E2, R | R2> =>
|
|
||||||
make((b: B) => Effect.flatMap(f(b), (a) => self.set(a)))
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unwrap a `Writable` that is wrapped in an `Effect`.
|
* Unwrap a `Writable` that is wrapped in an `Effect`.
|
||||||
*
|
|
||||||
* @category constructors
|
|
||||||
*/
|
*/
|
||||||
export const unwrap = <A, E, R, E1, R1>(
|
export const unwrap = <A, E, R, E1, R1>(
|
||||||
effect: Effect.Effect<Writable<A, E, R>, E1, R1>,
|
effect: Effect.Effect<Writable<A, E, R>, E1, R1>,
|
||||||
): Writable<A, E | E1, R | R1> =>
|
): Writable<A, E | E1, R | R1> => make(<B>(
|
||||||
make((value: A) => Effect.flatMap(effect, (w) => w.set(value)))
|
f: (a: A) => readonly [B, A]
|
||||||
|
) => Effect.flatMap(effect, w => w.modify(f)))
|
||||||
|
|||||||
Reference in New Issue
Block a user