{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE TypeFamilies #-}
module Internal.BuildPure
( PureBuilder
, createPure
) where
import Control.Monad.Catch (Exception, MonadThrow(..), SomeException)
import Control.Monad.Catch.Pure (CatchT, runCatchT)
import Control.Monad.Primitive (PrimMonad(..))
import Control.Monad.ST (ST)
import Control.Monad.Trans (MonadTrans(..))
import Capnp.Bits (WordCount)
import Capnp.TraversalLimit (LimitT, MonadLimit, evalLimitT)
import Data.Mutable (Thaw(..), createT)
newtype PureBuilder s a = PureBuilder (LimitT (PrimCatchT (ST s)) a)
deriving(Functor, Applicative, Monad, MonadThrow, MonadLimit)
instance PrimMonad (PureBuilder s) where
type PrimState (PureBuilder s) = s
primitive = PureBuilder . primitive
runPureBuilder :: WordCount -> PureBuilder s a -> ST s (Either SomeException a)
runPureBuilder limit (PureBuilder m) = runPrimCatchT $ evalLimitT limit m
createPure :: (MonadThrow m, Thaw a) => WordCount -> (forall s. PureBuilder s (Mutable s a)) -> m a
createPure limit m = throwLeft $ createT (runPureBuilder limit m)
where
throwLeft :: (Exception e, MonadThrow m) => Either e a -> m a
throwLeft (Left e) = throwM e
throwLeft (Right a) = pure a
newtype PrimCatchT m a = PrimCatchT (CatchT m a)
deriving(Functor, Applicative, Monad, MonadThrow)
runPrimCatchT :: Monad m => PrimCatchT m a -> m (Either SomeException a)
runPrimCatchT (PrimCatchT m) = runCatchT m
instance MonadTrans PrimCatchT where
lift = PrimCatchT . lift
instance PrimMonad m => PrimMonad (PrimCatchT m) where
type PrimState (PrimCatchT m) = PrimState m
primitive = lift . primitive