module Data.Crc32 (
      crc32
    , Crc32(..)
) where



import           Data.Bits
import           Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BSL
import           Data.Vector          (Vector, (!))
import qualified Data.Vector          as V
import           Data.Word
import           Text.Printf



table :: Vector Word32
table :: Vector Word32
table = Word32 -> Vector Word32
createCrc32Table Word32
0xedb88320

createCrc32Table :: Word32 -> Vector Word32
createCrc32Table :: Word32 -> Vector Word32
createCrc32Table Word32
poly = Int -> (Int -> Word32) -> Vector Word32
forall a. Int -> (Int -> a) -> Vector a
V.generate Int
256 ((Int -> Word32) -> Vector Word32)
-> (Int -> Word32) -> Vector Word32
forall a b. (a -> b) -> a -> b
$ \Int
n -> (Word32 -> Integer -> Word32) -> Word32 -> Vector Integer -> Word32
forall a b. (a -> b -> a) -> a -> Vector b -> a
V.foldl'
    (\Word32
acc Integer
_ -> if Word32 -> Bool
forall a. Integral a => a -> Bool
odd Word32
acc
        then Word32
poly Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
`xor` Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
shiftR Word32
acc Int
1
        else Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
shiftR Word32
acc Int
1
        )
    (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n)
    (Integer -> Int -> Vector Integer
forall a. Num a => a -> Int -> Vector a
V.enumFromN Integer
0 Int
8)

-- fn crc32_compute_table() -> [u32; 256] {
--     let mut crc32_table = [0; 256];
--
--     for n in 0..256 {
--         crc32_table[n as usize] = (0..8).fold(n as u32, |acc, _| {
--             match acc & 1 {
--                 1 => 0xedb88320 ^ (acc >> 1),
--                 _ => acc >> 1,
--             }
--         });
--     }
--
--     crc32_table
-- }

newtype Crc32 = Crc32 Word32
    deriving (Crc32 -> Crc32 -> Bool
(Crc32 -> Crc32 -> Bool) -> (Crc32 -> Crc32 -> Bool) -> Eq Crc32
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Crc32 -> Crc32 -> Bool
== :: Crc32 -> Crc32 -> Bool
$c/= :: Crc32 -> Crc32 -> Bool
/= :: Crc32 -> Crc32 -> Bool
Eq, Eq Crc32
Eq Crc32
-> (Crc32 -> Crc32 -> Ordering)
-> (Crc32 -> Crc32 -> Bool)
-> (Crc32 -> Crc32 -> Bool)
-> (Crc32 -> Crc32 -> Bool)
-> (Crc32 -> Crc32 -> Bool)
-> (Crc32 -> Crc32 -> Crc32)
-> (Crc32 -> Crc32 -> Crc32)
-> Ord Crc32
Crc32 -> Crc32 -> Bool
Crc32 -> Crc32 -> Ordering
Crc32 -> Crc32 -> Crc32
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Crc32 -> Crc32 -> Ordering
compare :: Crc32 -> Crc32 -> Ordering
$c< :: Crc32 -> Crc32 -> Bool
< :: Crc32 -> Crc32 -> Bool
$c<= :: Crc32 -> Crc32 -> Bool
<= :: Crc32 -> Crc32 -> Bool
$c> :: Crc32 -> Crc32 -> Bool
> :: Crc32 -> Crc32 -> Bool
$c>= :: Crc32 -> Crc32 -> Bool
>= :: Crc32 -> Crc32 -> Bool
$cmax :: Crc32 -> Crc32 -> Crc32
max :: Crc32 -> Crc32 -> Crc32
$cmin :: Crc32 -> Crc32 -> Crc32
min :: Crc32 -> Crc32 -> Crc32
Ord)

instance Show Crc32 where show :: Crc32 -> String
show (Crc32 Word32
crc) = String -> Word32 -> String
forall r. PrintfType r => String -> r
printf String
"%#08x" Word32
crc

-- | CRC32 checksum.
--
-- >>> import Data.ByteString.Lazy.Char8
-- >>> crc32 (pack "The quick brown fox jumps over the lazy dog")
-- 0x414fa339
--
-- >>> crc32 (pack "123456789")
-- 0xcbf43926
crc32 :: ByteString -> Crc32
crc32 :: ByteString -> Crc32
crc32 ByteString
bs =
    let Crc32 Word32
crcResult = (Crc32 -> Word8 -> Crc32) -> Crc32 -> ByteString -> Crc32
forall a. (a -> Word8 -> a) -> a -> ByteString -> a
BSL.foldl' (\(Crc32 Word32
crc) Word8
byte -> Word32 -> Crc32
Crc32 (Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
xor (Word32
crc Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`shiftR` Int
8) (Vector Word32
table Vector Word32 -> Int -> Word32
forall a. Vector a -> Int -> a
! Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32
crc Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
0xff) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
byte)))) (Word32 -> Crc32
Crc32 Word32
0xffffffff) ByteString
bs
    in Word32 -> Crc32
Crc32 (Word32 -> Word32
forall a. Bits a => a -> a
complement Word32
crcResult)