Skip to content

Instantly share code, notes, and snippets.

@chrisdone
Last active April 17, 2022 22:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrisdone/9e0466e883cda9e72af95b3b6001466c to your computer and use it in GitHub Desktop.
Save chrisdone/9e0466e883cda9e72af95b3b6001466c to your computer and use it in GitHub Desktop.
Halogen.Wormhole
-- | 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
@chrisdone
Copy link
Author

Remember to unsubscribe existing eventSource if responding to inputs.

@chrisdone
Copy link
Author

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