{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
module Data.Capnp.Convert
( msgToBuilder
, msgToLBS
, msgToBS
, msgToValue
, bsToMsg
, bsToValue
, lbsToMsg
, lbsToValue
, valueToBuilder
, valueToBS
, valueToLBS
, valueToMsg
) where
import Control.Monad ((>=>))
import Control.Monad.Catch (MonadThrow)
import Data.Foldable (foldlM)
import Data.Functor.Identity (runIdentity)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Builder as BB
import qualified Data.ByteString.Lazy as LBS
import Data.Capnp.Classes
import Codec.Capnp (getRoot, setRoot)
import Data.Capnp.TraversalLimit (LimitT, MonadLimit, evalLimitT)
import Data.Mutable (freeze)
import qualified Data.Capnp.Message as M
limitFromMsg :: (MonadThrow m, M.Message m msg) => msg -> m Int
limitFromMsg msg = do
messageWords <- countMessageWords
pure (messageWords * 4)
where
countMessageWords = do
segCount <- M.numSegs msg
foldlM
(\total i -> do
words <- M.getSegment msg i >>= M.numWords
pure (words + total)
)
0
[0..segCount - 1]
msgToBuilder :: M.ConstMsg -> BB.Builder
msgToBuilder = runIdentity . M.encode
msgToLBS :: M.ConstMsg -> LBS.ByteString
msgToLBS = BB.toLazyByteString . msgToBuilder
msgToBS :: M.ConstMsg -> BS.ByteString
msgToBS = LBS.toStrict . msgToLBS
msgToValue :: (MonadThrow m, M.Message (LimitT m) msg, M.Message m msg, FromStruct msg a) => msg -> m a
msgToValue msg = do
limit <- limitFromMsg msg
evalLimitT limit (getRoot msg)
bsToMsg :: MonadThrow m => BS.ByteString -> m M.ConstMsg
bsToMsg = M.decode
bsToValue :: (MonadThrow m, FromStruct M.ConstMsg a) => BS.ByteString -> m a
bsToValue = bsToMsg >=> msgToValue
lbsToMsg :: MonadThrow m => LBS.ByteString -> m M.ConstMsg
lbsToMsg = bsToMsg . LBS.toStrict
lbsToValue :: (MonadThrow m, FromStruct M.ConstMsg a) => LBS.ByteString -> m a
lbsToValue = bsToValue . LBS.toStrict
valueToBuilder :: (MonadLimit m, M.WriteCtx m s, Cerialize s a, ToStruct (M.MutMsg s) (Cerial (M.MutMsg s) a)) => a -> m BB.Builder
valueToBuilder val = msgToBuilder <$> (valueToMsg val >>= freeze)
valueToBS :: (MonadLimit m, M.WriteCtx m s, Cerialize s a, ToStruct (M.MutMsg s) (Cerial (M.MutMsg s) a)) => a -> m BS.ByteString
valueToBS = fmap LBS.toStrict . valueToLBS
valueToLBS :: (MonadLimit m, M.WriteCtx m s, Cerialize s a, ToStruct (M.MutMsg s) (Cerial (M.MutMsg s) a)) => a -> m LBS.ByteString
valueToLBS = fmap BB.toLazyByteString . valueToBuilder
valueToMsg :: (MonadLimit m, M.WriteCtx m s, Cerialize s a, ToStruct (M.MutMsg s) (Cerial (M.MutMsg s) a)) => a -> m (M.MutMsg s)
valueToMsg val = do
msg <- M.newMessage
ret <- cerialize msg val
setRoot ret
pure msg