packages feed

helic-0.6.0.0: lib/Helic/Interpreter/GtkMain.hs

{-# options_haddock prune #-}

-- |An interpreter for 'GtkMain' that uses 'MVar's.
-- Internal.
module Helic.Interpreter.GtkMain where

import Conc (Lock, interpretLockReentrant, interpretSync, lock)
import Polysemy.Opaque (Opaque)
import qualified Sync

import qualified Helic.Effect.GtkMain as GtkMain
import Helic.Effect.GtkMain (GtkMain)
import Helic.GtkMain (gtkResource)

data GtkLock =
  GtkLock
  deriving stock (Eq, Show)

data StartGtkMain =
  StartGtkMain
  deriving stock (Eq, Show)

newtype GtkResource s =
  GtkResource { unGtkResource :: s }
  deriving stock (Eq, Show)

-- TODO Access needs to be a scope to ensure it must be executed
-- this means that access/request and run/running must be two separate effects

-- |Interpret the GTK main loop communication bridge with 'MVar's.
handleGtkMain ::
  ∀ s wait restart e m r a .
  TimeUnit wait =>
  TimeUnit restart =>
  Members [Resource, Lock, Sync StartGtkMain, Sync (GtkResource s)] r =>
  wait ->
  restart ->
  GtkMain s m a ->
  Tactical e m r a
handleGtkMain wait restart = \case
  GtkMain.Access ms -> do
    lock do
      Sync.try >>= \case
        Just (GtkResource s) ->
          pureT s
        Nothing ->
          runTSimple ms
  GtkMain.Request ms -> do
    Sync.clear @(GtkResource _)
    Sync.putTry StartGtkMain
    Sync.wait wait >>= \case
      Just (GtkResource s) ->
        pureT s
      Nothing ->
        runTSimple ms
  GtkMain.Run ma -> do
    Sync.clear @StartGtkMain
    Sync.clear @(GtkResource _)
    runTSimple ma <* do
      Sync.clear @(GtkResource _)
      Sync.takeWait @StartGtkMain restart
  GtkMain.Running s ->
    pureT =<< Sync.putBlock (GtkResource s)

-- |Interpret the GTK main loop communication bridge with 'MVar's.
interpretGtkMain ::
  ∀ s wait restart r .
  TimeUnit wait =>
  TimeUnit restart =>
  Members [Mask, Resource, Race, Embed IO] r =>
  wait ->
  restart ->
  InterpreterFor (GtkMain s) r
interpretGtkMain wait restart =
  interpretSync .
  interpretLockReentrant .
  interpretSync @StartGtkMain .
  interpretH (handleGtkMain wait restart) .
  raiseUnder3

-- |Scope an effect that uses a GTK main loop resource by acquiring it via 'GtkMain'.
interpretWithGtk ::
  ∀ e s r .
  Members [GtkMain s, Log] r =>
  (∀ q r0 x . s -> e (Sem r0) x -> Tactical e (Sem r0) (Stop Text : Opaque q : r) x) ->
  InterpreterFor (Scoped_ e !! Text) r
interpretWithGtk =
  interpretScopedResumableH \ () -> (=<< gtkResource)