{-# LANGUAGE RankNTypes #-} {- | Module : Control.Quiver.Binary Description : Support Binary inside Quiver Copyright : (c) Ivan Lazar Miljenovic License : MIT Maintainer : Ivan.Miljenovic@gmail.com This module provides functions for encoding\/decoding values within a Quiver. For any I\/O operations, use the functions provided by the package. -} module Control.Quiver.Binary ( -- * Simple encoding\/decoding spput , spget -- * Conversions to\/from ByteStrings , spdecode , spdecodeL , spencode , spencodeL ) where import Control.Quiver.ByteString import Control.Quiver.SP import Data.Binary import Data.Binary.Get import Data.Binary.Put import Data.ByteString (ByteString) import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L -------------------------------------------------------------------------------- -- | Encode all values. spput :: (Binary a) => SConsumer a PutM e spput = sptraverse_ put -- | Decode all values. spget :: (Binary a) => SProducer a Get e spget = spuntilM isEmpty get spuntilM :: (Monad m) => m Bool -> m a -> SProducer a m e spuntilM chk prod = go where go = do done <- qlift chk if done then spcomplete else do a <- qlift prod a >:> go -------------------------------------------------------------------------------- -- | Decode all values from the provided stream of strict ByteStrings. Note -- that the error message does not return the 'ByteOffset' from the -- 'Decoder' as it will probably not match the actual location of the -- source ByteString. spdecode :: (Binary a, Monad m) => SP ByteString a m String spdecode = runDecode nextD where nextD = runGetIncremental get runDecode d = case d of Fail b' _ err -> if B.null b' then spcomplete -- No more input! (should probably also check the offset) else spfailed err Partial p -> spfetch >>= runDecode . p Done b' _ a -> a >:> runDecode (nextD `pushChunk` b') -- TODO: consider using state internally to keep track of the offset throughout the entire thing -- | Decode all values from the provided stream of lazy ByteStrings. Note -- that the error message does not return the 'ByteOffset' from the -- 'Decoder' as it will probably not match the actual location of the -- source ByteString. spdecodeL :: forall a m. (Binary a, Monad m) => SP L.ByteString a m String spdecodeL = toChunks >->> spdecode >&> snd -- | Encode all values to a stream of strict ByteStrings. spencode :: (Binary a, Functor m) => SP a ByteString m () spencode = spencodeL >->> toChunks >&> fst -- | Encode all values to a stream of lazy ByteStrings. spencodeL :: (Binary a) => SP a L.ByteString m () spencodeL = sppure encode