-
-
Save chrisdone/9e0466e883cda9e72af95b3b6001466c to your computer and use it in GitHub Desktop.
Halogen.Wormhole
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- | A wormhole makes it easy to implement a pub/sub or hooks-like | |
-- functionality. | |
-- | |
-- EXAMPLE: | |
-- | |
-- in a component's initializer: | |
-- pizzasWormhole <- newWormhole | |
-- | |
-- in a compment's eval handler: | |
-- emitWormhole SomePizza pizzasWormhole | |
-- | |
-- elsewhere: | |
-- H.subscribe (PizzaArrived pizzasEventSource) | |
-- | |
module Halogen.Wormhole | |
( Wormhole | |
, newWormhole | |
, emitWormhole | |
, wormholeEventsource | |
) where | |
import Data.Array as Array | |
import Data.Foldable | |
import Data.Map (Map) | |
import Data.Map as M | |
import Data.Traversable | |
import Effect | |
import Effect.Aff | |
import Effect.Ref as Ref | |
import Halogen as H | |
import Halogen.Query.EventSource | |
import Prelude | |
-- | A wormhole maintains a set of emitters. | |
data Wormhole a = | |
Wormhole | |
{ emittersRef :: Ref.Ref (Map Int (Emitter Effect a)) | |
, eventSource :: EventSource Aff a | |
, countRef :: Ref.Ref Int | |
} | |
-- | Create a new wormhole. | |
newWormhole :: forall a. Effect (Wormhole a) | |
newWormhole = do | |
emittersRef <- Ref.new M.empty | |
countRef <- Ref.new 0 | |
let eventSource = | |
effectEventSource | |
(\emitter -> do | |
id <- Ref.modify (_ + 1) countRef | |
_ <- H.liftEffect $ Ref.modify (M.insert id emitter) emittersRef | |
pure (Finalizer (Ref.modify_ (M.delete id) emittersRef))) | |
pure (Wormhole {emittersRef, eventSource, countRef}) | |
-- | Emit a value to a wormhole. | |
emitWormhole :: forall a. a -> Wormhole a -> Effect Unit | |
emitWormhole value (Wormhole {emittersRef}) = do | |
emitters <- Ref.read emittersRef | |
traverse_ (\emitter -> emit emitter value) emitters | |
-- | Get the event source so that we can subscribe to it. | |
wormholeEventsource :: forall a. Wormhole a -> EventSource Aff a | |
wormholeEventsource (Wormhole {eventSource}) = eventSource |
Q: do you couple an initial value with the wormhole, or consider them entirely separate? Arguably, a wormhole is merely an optimization you can add to an existing codepath already using component inputs.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Remember to unsubscribe existing eventSource if responding to inputs.