From 17686e68c321b48addde514b8bcc0d8c2cf8220e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sun, 20 Apr 2025 04:34:01 +0200 Subject: [PATCH] SubscriptionSubRef --- packages/reffuse/src/SubscriptionSubRef.ts | 53 ++++++++++++---------- packages/reffuse/src/index.ts | 1 + 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/packages/reffuse/src/SubscriptionSubRef.ts b/packages/reffuse/src/SubscriptionSubRef.ts index dbc7f01..60e08ac 100644 --- a/packages/reffuse/src/SubscriptionSubRef.ts +++ b/packages/reffuse/src/SubscriptionSubRef.ts @@ -1,7 +1,9 @@ -import { Effect, Effectable, PubSub, Readable, Ref, Stream, Subscribable, SubscriptionRef, SynchronizedRef } from "effect" +import { Effect, Effectable, Readable, Ref, Stream, Subscribable, SubscriptionRef, SynchronizedRef } from "effect" -export interface SubscriptionSubRef extends SubscriptionRef.SubscriptionRef { +export interface SubscriptionSubRef extends SubscriptionRef.SubscriptionRef { + readonly ref: SubscriptionRef.SubscriptionRef + /** * A stream containing the current value of the `Ref` as well as all changes * to that value. @@ -9,56 +11,59 @@ export interface SubscriptionSubRef extends SubscriptionRef.Subscripti readonly changes: Stream.Stream } + const synchronizedRefVariance = { _A: (_: any) => _ } const subscriptionRefVariance = { _A: (_: any) => _ } -class SubscriptionSubRefImpl extends Effectable.Class implements SubscriptionSubRef { +class SubscriptionSubRefImpl extends Effectable.Class implements SubscriptionSubRef { readonly [Readable.TypeId]: Readable.TypeId = Readable.TypeId readonly [Subscribable.TypeId]: Subscribable.TypeId = Subscribable.TypeId readonly [Ref.RefTypeId]: Ref.Ref.Variance[Ref.RefTypeId] = { _A: (_: any) => _ } readonly [SynchronizedRef.SynchronizedRefTypeId]: SynchronizedRef.SynchronizedRef.Variance[SynchronizedRef.SynchronizedRefTypeId] = synchronizedRefVariance readonly [SubscriptionRef.SubscriptionRefTypeId]: SubscriptionRef.SubscriptionRef.Variance[SubscriptionRef.SubscriptionRefTypeId] = subscriptionRefVariance + readonly get: Effect.Effect + constructor( - readonly ref: Ref.Ref, - readonly pubsub: PubSub.PubSub, - readonly semaphore: Effect.Semaphore, + readonly ref: SubscriptionRef.SubscriptionRef, + readonly select: (value: B) => A, + readonly setter: (value: A) => B, ) { super() - this.get = Ref.get(this.ref) + this.get = Ref.get(this.ref).pipe(Effect.map(this.select)) } commit() { return this.get } - readonly get: Effect.Effect - get changes(): Stream.Stream { - return Ref.get(this.ref).pipe( - Effect.flatMap(a => Effect.map( - Stream.fromPubSub(this.pubsub, { scoped: true }), + return this.get.pipe( + Effect.map(a => this.ref.changes.pipe( + Stream.map(this.select), s => Stream.concat(Stream.make(a), s), )), - - this.semaphore.withPermits(1), - Stream.unwrapScoped, + Stream.unwrap, ) } - modify(f: (a: A) => readonly [B, A]): Effect.Effect { - return this.modifyEffect((a) => Effect.succeed(f(a))) + modify(f: (a: A) => readonly [C, A]): Effect.Effect { + return this.modifyEffect(a => Effect.succeed(f(a))) } - modifyEffect(f: (a: A) => Effect.Effect): Effect.Effect { - return Ref.get(this.ref).pipe( + modifyEffect(f: (a: A) => Effect.Effect): Effect.Effect { + return this.get.pipe( Effect.flatMap(f), - Effect.flatMap(([b, a]) => Ref.set(this.ref, a).pipe( - Effect.as(b), - Effect.zipLeft(PubSub.publish(this.pubsub, a)) + Effect.flatMap(([b, a]) => Ref.set(this.ref, this.setter(a)).pipe( + Effect.as(b) )), - - this.semaphore.withPermits(1) ) } } + + +export const make = ( + ref: SubscriptionRef.SubscriptionRef, + select: (value: B) => A, + setter: (value: A) => B, +): SubscriptionSubRef => new SubscriptionSubRefImpl(ref, select, setter) diff --git a/packages/reffuse/src/index.ts b/packages/reffuse/src/index.ts index 01fb88f..593b50f 100644 --- a/packages/reffuse/src/index.ts +++ b/packages/reffuse/src/index.ts @@ -4,3 +4,4 @@ export * as ReffuseExtension from "./ReffuseExtension.js" export * as ReffuseNamespace from "./ReffuseNamespace.js" export * as ReffuseRuntime from "./ReffuseRuntime.js" export * as SetStateAction from "./SetStateAction.js" +export * as SubscriptionSubRef from "./SubscriptionSubRef.js"