packages feed

bytepatch-0.3.0: src/StreamPatch/Apply.hs

module StreamPatch.Apply where

import           StreamPatch.Stream
import           StreamPatch.Patch
import qualified StreamPatch.Patch.Binary   as Bin
import           StreamPatch.Patch.Binary   ( BinRep )

import           Data.Vinyl
import qualified Data.ByteString            as BS
import qualified Data.ByteString.Builder    as BB
import qualified Data.ByteString.Lazy       as BL
import           Control.Monad.State
import           Util

-- TODO how to clean up, use Either monad inside m? (lift didn't work)
applyBinFwd
    :: forall a m. (MonadFwdStream m, Chunk m ~ BS.ByteString, BinRep a)
    => Bin.Cfg
    -> [Patch 'FwdSeek '[Bin.MetaStream] a]
    -> m (Either (Bin.Error a) ())
applyBinFwd cfg = traverseM_ $ \(Patch a s (FunctorRec (Flap m :& RNil))) -> do
    case Bin.toBinRep' a of
      Left err -> return $ Left err
      Right bs -> do
        advance s
        bsStream <- readahead $ fromIntegral $ BS.length bs
        case Bin.check cfg bsStream m of
          Left err -> return $ Left err
          Right () -> do
            overwrite bs
            return $ Right ()

runPureFwdBin
    :: BinRep a
    => Bin.Cfg
    -> [Patch 'FwdSeek '[Bin.MetaStream] a]
    -> BS.ByteString
    -> Either (Bin.Error a) BL.ByteString
runPureFwdBin cfg ps bs =
    let (mErr, (bsRemaining, bbPatched)) = runState (applyBinFwd cfg ps) (bs, mempty)
        bbPatched' = bbPatched <> BB.byteString bsRemaining
     in case mErr of
          Left err -> Left err
          Right () -> Right $ BB.toLazyByteString bbPatched'

applySimpleFwd
    :: (MonadFwdStream m, Chunk m ~ a)
    => [Patch 'FwdSeek '[] a]
    -> m ()
applySimpleFwd =
    mapM_ $ \(Patch a s (FunctorRec RNil)) -> advance s >> overwrite a

-- stupid because no monotraversable :<
runPureSimpleFwdList
    :: [Patch 'FwdSeek '[] [a]]
    -> [a]
    -> [a]
runPureSimpleFwdList ps start =
    let ((), (remaining, patched)) = runState (applySimpleFwd ps) (start, mempty)
     in patched <> remaining