-- |
-- Module      : Crypto.Store.Util
-- License     : BSD-style
-- Maintainer  : Olivier Chéron <olivier.cheron@gmail.com>
-- Stability   : experimental
-- Portability : unknown
--
--
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE MagicHash #-}
module Crypto.Store.Util
    ( (&&!)
    , reverseBytes
    , constAllEq
    , mapLeft
    ) where

import           Data.Bits
import           Data.ByteArray (ByteArray, ByteArrayAccess)
import qualified Data.ByteArray as B
import           Data.List
import           Data.Word

import GHC.Exts

-- | This is a strict version of &&.
(&&!) :: Bool -> Bool -> Bool
&&! :: Bool -> Bool -> Bool
(&&!) Bool
x Bool
y = Int# -> Bool
isTrue# (Int# -> Int# -> Int#
andI# (Bool -> Int#
forall a. a -> Int#
getTag# Bool
x) (Bool -> Int#
forall a. a -> Int#
getTag# Bool
y))
  where getTag# :: a -> Int#
getTag# !a
z = a -> Int#
forall a. a -> Int#
dataToTag# a
z
infixr 3 &&!

-- | Reverse a bytearray.
reverseBytes :: ByteArray ba => ba -> ba
#if MIN_VERSION_memory(0,14,18)
reverseBytes :: ba -> ba
reverseBytes = ba -> ba
forall bs. ByteArray bs => bs -> bs
B.reverse
#else
reverseBytes = B.pack . reverse . B.unpack
#endif

-- | Test if all bytes in a bytearray are equal to the value specified.  Runs in
-- constant time.
constAllEq :: ByteArrayAccess ba => Word8 -> ba -> Bool
constAllEq :: Word8 -> ba -> Bool
constAllEq Word8
b = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0) (Word8 -> Bool) -> (ba -> Word8) -> ba -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word8 -> Word8 -> Word8) -> Word8 -> [Word8] -> Word8
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Word8 -> Word8 -> Word8
fn Word8
0 ([Word8] -> Word8) -> (ba -> [Word8]) -> ba -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ba -> [Word8]
forall a. ByteArrayAccess a => a -> [Word8]
B.unpack
  where fn :: Word8 -> Word8 -> Word8
fn Word8
acc Word8
x = Word8
acc Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
xor Word8
b Word8
x

-- | Map over the left value.
mapLeft :: (a -> b) -> Either a c -> Either b c
mapLeft :: (a -> b) -> Either a c -> Either b c
mapLeft a -> b
f (Left a
a)  = b -> Either b c
forall a b. a -> Either a b
Left (a -> b
f a
a)
mapLeft a -> b
_ (Right c
c) = c -> Either b c
forall a b. b -> Either a b
Right c
c