packages feed

bluefin-internal-0.2.0.0: src/Bluefin/Internal/Exception/Scoped.hs

module Bluefin.Internal.Exception.Scoped
  ( Exception,
    try,
    throw,
  )
where

import Bluefin.Internal.Key (Key, eqKey, newKey)
import Control.Exception (throwIO, tryJust)
import qualified Control.Exception
import Data.Type.Equality ((:~~:) (HRefl))
import Data.Kind (Type)

try :: (Exception e -> IO a) -> IO (Either e a)
try k = do
  key <- newKey
  tryJust
    (check key)
    (k (MkException key))

throw :: Exception e -> e -> IO a
throw ex e = throwIO (MkInFlight ex e)

-- Corresponds to what Bluefin calls an "Exception", i.e. "a handle to
-- an exception" or "the capability to throw an exception".
newtype Exception (e :: Type) = MkException (Key e)

-- InFlight is like Locker from vault.  MkInflight is like lock from
-- vault.
data InFlight = forall e. MkInFlight !(Exception e) !e

instance Show InFlight where
  show _ = "In-flight scoped exception"

instance Control.Exception.Exception InFlight

-- Like unlock from vault
check :: Key a -> InFlight -> Maybe a
check k1 (MkInFlight (MkException k2) e) = fmap (\HRefl -> e) (k1 `eqKey` k2)