src/Codec/Goat/Util.hs
{- |
Module : Codec.Goat.Util
Description : Various utility functions
Copyright : (c) Daniel Lovasko, 2016-2017
License : BSD3
Maintainer : Daniel Lovasko <daniel.lovasko@gmail.com>
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