capnp-0.2.0.0: lib/Internal/BuildPure.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE TypeFamilies #-}
{- |
Module: Internal.BuildPure
Description: Helpers for building capnproto messages in pure code.
This module provides some helpers for building capnproto messages and values
in pure code, using the low-level API.
-}
module Internal.BuildPure
( PureBuilder
, createPure
) where
import Control.Monad.Catch (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 Data.Capnp.TraversalLimit (LimitT, MonadLimit, evalLimitT)
import Data.Mutable (Thaw(..), createT)
-- | 'PureBuilder' is a monad transformer stack with the instnaces needed
-- manipulate mutable messages. @'PureBuilder' s a@ is morally equivalent
-- to @'LimitT ('CatchT' ('ST' s)) a@
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 :: Int -> PureBuilder s a -> ST s (Either SomeException a)
runPureBuilder limit (PureBuilder m) = runPrimCatchT $ evalLimitT limit m
-- | @'createPure' limit m@ creates a capnproto value in pure code according
-- to @m@, then freezes it without copying. If @m@ calls 'throwM' then
-- 'createPure' returns a 'Left' with the exception.
createPure :: Thaw a => Int -> (forall s. PureBuilder s (Mutable s a)) -> Either SomeException a
createPure limit m = createT (runPureBuilder limit m)
-- | 'PrimCatchT' is a trivial wrapper around 'CatchT', which implements
-- 'PrimMonad'. This is a temporary workaround for:
--
-- https://github.com/ekmett/exceptions/issues/65
--
-- If we can get that issue fixed, we can delete this and just bump the
-- min bound on the exceptions package.
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