{- | Module : Codec.Goat.Util Description : Various utility functions Copyright : (c) Daniel Lovasko, 2016-2017 License : BSD3 Maintainer : Daniel Lovasko Stability : stable Portability : portable Various utility functions used throughout the codebase. -} module Codec.Goat.Util ( aiGetByteString , aiPutByteString , bool , first , fromBools , inBounds , packBits , select , sub , toBools , unpackBits ) where import Data.Bits import Data.Int import Data.List.Split (chunksOf) import Data.Serialize import Data.Word import qualified Data.ByteString as B -- | Check whether a value falls between the bounds (inclusive). inBounds :: (Ord a) => (a, a) -- ^ bounds -> a -- ^ value -> Bool -- ^ decision inBounds (lo, hi) x = lo <= x && x <= hi -- | Correct subtraction of two unsigned integers. sub :: Word32 -- ^ first word -> Word32 -- ^ second word -> Int64 -- ^ result sub a b = fromIntegral a - fromIntegral b -- | Pack a list of bits into a more compact form. packBits :: [Bool] -- ^ bits -> B.ByteString -- ^ bytestring packBits xs = B.pack $ map fromBools (chunksOf 8 xs) -- | Unpack a compact block of bytes into a list of bools. unpackBits :: B.ByteString -- ^ bits -> [Bool] -- ^ bytestring unpackBits b = concatMap toBools (B.unpack b) -- | Functional equivalent of the 'if/then/else' construct. bool :: a -- ^ True option -> a -- ^ False option -> Bool -- ^ bool -> a -- ^ result bool x _ True = x bool _ y False = y -- | Convert a Bits instance into a list of bools. toBools :: (FiniteBits b) => b -- ^ Bits instance -> [Bool] -- ^ bits toBools bits = map (testBit bits) [0..finiteBitSize bits-1] -- | Convert a list of bools into a Bits instance. fromBools :: (Num b, FiniteBits b) => [Bool] -- ^ bits -> b -- ^ Bits instance fromBools = foldr (\b i -> bool (bit 0) 0 b .|. shift i 1) 0 -- | Select only certain elements from the list based on the boolean values. select :: [a] -- ^ list -> [Bool] -- ^ presence flags -> [a] -- ^ filtered list select [] _ = [] select _ [] = [] select (x:xs) (b:bs) = bool (x : select xs bs) (select xs bs) b -- | Apply a function to the first element of a pair. first :: (a -> b) -- ^ function -> (a, x) -- ^ old pair -> (b, x) -- ^ new pair first f (a, x) = (f a, x) -- | Architecture-independent serialization of a strict ByteString. aiPutByteString :: B.ByteString -- ^ bytestring to parse -> Put -- ^ writer aiPutByteString bs = putListOf putWord8 (B.unpack bs) -- | Architecture-independent deserialization of a lazy ByteString. aiGetByteString :: Get B.ByteString -- ^ reader aiGetByteString = B.pack <$> getListOf getWord8