-- |-- Module : Data.Byteable-- License : BSD-style-- Maintainer : Vincent Hanquez <vincent@snarc.org>-- Stability : experimental-- Portability : good--
module Data.Byteable
( Byteable(..)
, constEqBytes
) where
import Foreign.Ptr (Ptr, plusPtr)
import Foreign.ForeignPtr (withForeignPtr)
import Data.ByteString (ByteString)
import Data.List (foldl')
import Data.Word (Word8)
import qualified Data.ByteString as B (length, zipWith)
import qualified Data.ByteString.Internal as B (toForeignPtr)
-- | Class of things that can generate sequence of bytes
class Byteablea where
-- | Convert a byteable type to a bytestringtoBytes :: a -> ByteString-- | Return the size of the byteable .byteableLength :: a -> IntbyteableLength = B.length.toBytes-- | Provide a way to look at the data of a byteable type with a ptr.withBytePtr :: a -> (PtrWord8 -> IOb) -> IObwithBytePtraf = withForeignPtrfptr$ \ptr -> f (ptr`plusPtr`off)
where (fptr, off, _) = B.toForeignPtr$toBytesa
instance ByteableByteString where
toBytesbs = bs-- | A constant time equality test for 2 byteable objects.---- If objects are of 2 different sizes, the function will abort early-- without comparing any bytes.---- compared to == , this function will go over all the bytes-- present before yielding a result even when knowing the-- overall result early in the processing.constEqBytes :: Byteable a =>a -> a -> BoolconstEqBytesab = constEqByteString (toBytesa) (toBytesb)
{-# RULES "constEqBytes/ByteString" constEqBytes = constEqByteString #-}{-# INLINE constEqByteString #-}constEqByteString :: ByteString -> ByteString -> BoolconstEqByteStringab
| len/=B.lengthb = False
| otherwise = foldl'(&&!)True$B.zipWith(==)ab
where len = B.lengtha(&&!) :: Bool -> Bool -> BoolTrue&&!True = TrueTrue&&!False = FalseFalse&&!True = FalseFalse&&!False = False