packages feed

hnix-store-remote-0.4.2.0: src/System/Nix/Store/Remote/Binary.hs

{-|
Description : Utilities for packing stuff
Maintainer  : srk <srk@48.io>
|-}
module System.Nix.Store.Remote.Binary where

import           Control.Monad
import           Data.Binary.Get
import           Data.Binary.Put
import           Data.ByteString                ( ByteString )
import qualified Data.ByteString.Lazy          as BSL

putInt :: Integral a => a -> Put
putInt = putWord64le . fromIntegral

getInt :: Integral a => Get a
getInt = fromIntegral <$> getWord64le

putMany :: Foldable t => (a -> Put) -> t a -> Put
putMany printer xs = do
  putInt (length xs)
  mapM_ printer xs

getMany :: Get a -> Get [a]
getMany parser = do
  count <- getInt
  replicateM count parser

-- length prefixed string packing with padding to 8 bytes
putByteStringLen :: BSL.ByteString -> Put
putByteStringLen x = do
  putInt len
  putLazyByteString x
  when (len `mod` 8 /= 0) $ pad $ 8 - (len `mod` 8)
 where
  len :: Int
  len = fromIntegral $ BSL.length x
  pad count = sequence_ $ replicate count (putWord8 0)

putByteStrings :: Foldable t => t BSL.ByteString -> Put
putByteStrings = putMany putByteStringLen

getByteStringLen :: Get ByteString
getByteStringLen = do
  len <- getInt
  st  <- getLazyByteString len
  when (len `mod` 8 /= 0) $ do
    pads <- unpad $ fromIntegral $ 8 - (len `mod` 8)
    unless (all (== 0) pads) $ fail $ "No zeroes" <> show (st, len, pads)
  pure $ BSL.toStrict st
  where unpad x = sequence $ replicate x getWord8

getByteStrings :: Get [ByteString]
getByteStrings = getMany getByteStringLen