snappy-c-0.1.0: src/Codec/Compression/SnappyC/Internal/Checksum.hs
-- | Intended for qualified import:
--
-- > import Codec.Compression.SnappyC.Internal.Checksum (Checksum)
-- > import Codec.Compression.SnappyC.Internal.Checksum qualified as Checksum
module Codec.Compression.SnappyC.Internal.Checksum
( -- * Type
Checksum -- Opaque
-- ** Calculating checksums
, calculate
-- ** Encoding and decoding checksums
, encode
, decode
) where
import Data.ByteString qualified as Strict (ByteString)
import Data.ByteString qualified as BS.Strict
import Data.Bits
import Data.Digest.CRC32C
import Data.Word
-- | Masked CRC32C checksum
newtype Checksum = Checksum { getChecksum :: Word32 }
deriving newtype (Show, Eq)
-- | Calculate
calculate :: Strict.ByteString -> Checksum
calculate =
Checksum . maskChecksum . crc32c
where
maskChecksum :: Word32 -> Word32
maskChecksum = (+ 0xa282ead8) . (`rotateR` 15)
-- | Encode
encode :: Checksum -> Strict.ByteString
encode =
BS.Strict.pack . toLittleEndian . getChecksum
where
toLittleEndian :: Word32 -> [Word8]
toLittleEndian s =
[ fromIntegral (s .&. 0x000000ff)
, fromIntegral $ shiftR (s .&. 0x0000ff00) 8
, fromIntegral $ shiftR (s .&. 0x00ff0000) 16
, fromIntegral $ shiftR (s .&. 0xff000000) 24
]
-- | Decode
--
-- __Precondition:__ Input must be exactly 4 bytes.
decode :: Strict.ByteString -> Checksum
decode =
Checksum . fromLittleEndian . BS.Strict.unpack
where
fromLittleEndian :: [Word8] -> Word32
fromLittleEndian [b1, b2, b3, b4] =
fromIntegral b1
.|. fromIntegral b2 `shiftL` 8
.|. fromIntegral b3 `shiftL` 16
.|. fromIntegral b4 `shiftL` 24
fromLittleEndian _ = error "Checksum.decode: precondition violated"