{-# LINE 1 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}

module Codec.Compression.LZ4.CTypes
  ( Lz4FrameException(..)
  , BlockSizeID(..)
  , BlockMode(..)
  , ContentChecksum(..)
  , BlockChecksum(..)
  , FrameType(..)
  , FrameInfo(..)
  , Preferences(..)
  , LZ4F_cctx
  , LZ4F_dctx
  , lz4FrameTypesTable
  ) where

import           Control.Exception (Exception, throwIO)
import           Data.Map (Map)
import qualified Data.Map as Map
import           Data.Typeable (Typeable)
import           Data.Word (Word32, Word64)
import           Foreign.Marshal.Utils (fillBytes)
import           Foreign.Ptr (Ptr, castPtr)
import           Foreign.Storable (Storable(..), poke)
import qualified Language.C.Types as C
import qualified Language.Haskell.TH as TH




data Lz4FrameException = Lz4FormatException String
  deriving (Eq, Ord, Show, Typeable)

instance Exception Lz4FrameException


data BlockSizeID
  = LZ4F_default
  | LZ4F_max64KB
  | LZ4F_max256KB
  | LZ4F_max1MB
  | LZ4F_max4MB
  deriving (Eq, Ord, Show)

instance Storable BlockSizeID where
  sizeOf _ = (4)
{-# LINE 50 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  alignment _ = 4
{-# LINE 51 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  peek p = do
    n <- peek (castPtr p :: Ptr Word32)
{-# LINE 53 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    case n of
      0 -> return LZ4F_default
{-# LINE 55 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
      4 -> return LZ4F_max64KB
{-# LINE 56 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
      5 -> return LZ4F_max256KB
{-# LINE 57 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
      6 -> return LZ4F_max1MB
{-# LINE 58 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
      7 -> return LZ4F_max4MB
{-# LINE 59 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
      _ -> throwIO $ Lz4FormatException $ "lz4 instance Storable BlockSizeID: encountered unknown LZ4F_blockSizeID_t: " ++ show n
  poke p i = poke (castPtr p :: Ptr Word32) $ case i of
{-# LINE 61 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    LZ4F_default -> 0
{-# LINE 62 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    LZ4F_max64KB -> 4
{-# LINE 63 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    LZ4F_max256KB -> 5
{-# LINE 64 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    LZ4F_max1MB -> 6
{-# LINE 65 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    LZ4F_max4MB -> 7
{-# LINE 66 "src/Codec/Compression/LZ4/CTypes.hsc" #-}


data BlockMode
  = LZ4F_blockLinked
  | LZ4F_blockIndependent
  deriving (Eq, Ord, Show)

instance Storable BlockMode where
  sizeOf _ = (4)
{-# LINE 75 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  alignment _ = 4
{-# LINE 76 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  peek p = do
    n <- peek (castPtr p :: Ptr Word32)
{-# LINE 78 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    case n of
      0 -> return LZ4F_blockLinked
{-# LINE 80 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
      1 -> return LZ4F_blockIndependent
{-# LINE 81 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
      _ -> throwIO $ Lz4FormatException $ "lz4 instance Storable BlockMode: encountered unknown LZ4F_blockMode_t: " ++ show n
  poke p mode = poke (castPtr p :: Ptr Word32) $ case mode of
{-# LINE 83 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    LZ4F_blockLinked -> 0
{-# LINE 84 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    LZ4F_blockIndependent -> 1
{-# LINE 85 "src/Codec/Compression/LZ4/CTypes.hsc" #-}


data ContentChecksum
  = LZ4F_noContentChecksum
  | LZ4F_contentChecksumEnabled
  deriving (Eq, Ord, Show)

instance Storable ContentChecksum where
  sizeOf _ = (4)
{-# LINE 94 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  alignment _ = 4
{-# LINE 95 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  peek p = do
    n <- peek (castPtr p :: Ptr Word32)
{-# LINE 97 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    case n of
      0 -> return LZ4F_noContentChecksum
{-# LINE 99 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
      1 -> return LZ4F_contentChecksumEnabled
{-# LINE 100 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
      _ -> throwIO $ Lz4FormatException $ "lz4 instance Storable ContentChecksum: encountered unknown LZ4F_contentChecksum_t: " ++ show n
  poke p mode = poke (castPtr p :: Ptr Word32) $ case mode of
{-# LINE 102 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    LZ4F_noContentChecksum -> 0
{-# LINE 103 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    LZ4F_contentChecksumEnabled -> 1
{-# LINE 104 "src/Codec/Compression/LZ4/CTypes.hsc" #-}


data BlockChecksum
  = LZ4F_noBlockChecksum
  | LZ4F_blockChecksumEnabled
  deriving (Eq, Ord, Show)

instance Storable BlockChecksum where
  sizeOf _ = (4)
{-# LINE 113 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  alignment _ = 4
{-# LINE 114 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  peek p = do
    n <- peek (castPtr p :: Ptr Word32)
{-# LINE 116 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    case n of
      0 -> return LZ4F_noBlockChecksum
{-# LINE 118 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
      1 -> return LZ4F_blockChecksumEnabled
{-# LINE 119 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
      _ -> throwIO $ Lz4FormatException $ "lz4 instance Storable BlockChecksum: encountered unknown LZ4F_blockChecksum_t: " ++ show n
  poke p mode = poke (castPtr p :: Ptr Word32) $ case mode of
{-# LINE 121 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    LZ4F_noBlockChecksum  -> 0
{-# LINE 122 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    LZ4F_blockChecksumEnabled -> 1
{-# LINE 123 "src/Codec/Compression/LZ4/CTypes.hsc" #-}


data FrameType
  = LZ4F_frame
  | LZ4F_skippableFrame
  deriving (Eq, Ord, Show)

instance Storable FrameType where
  sizeOf _ = (4)
{-# LINE 132 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  alignment _ = 4
{-# LINE 133 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  peek p = do
    n <- peek (castPtr p :: Ptr Word32)
{-# LINE 135 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    case n of
      0 -> return LZ4F_frame
{-# LINE 137 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
      1 -> return LZ4F_skippableFrame
{-# LINE 138 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
      _ -> throwIO $ Lz4FormatException $ "lz4 instance Storable FrameType: encountered unknown LZ4F_frameType_t: " ++ show n
  poke p mode = poke (castPtr p :: Ptr Word32) $ case mode of
{-# LINE 140 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    LZ4F_frame  -> 0
{-# LINE 141 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    LZ4F_skippableFrame -> 1
{-# LINE 142 "src/Codec/Compression/LZ4/CTypes.hsc" #-}


data FrameInfo = FrameInfo
  { blockSizeID         :: BlockSizeID
  , blockMode           :: BlockMode
  , contentChecksumFlag :: ContentChecksum
  , frameType           :: FrameType
  , contentSize         :: Word64
  , dictID              :: Word32 -- ^ @unsigned int@ in @lz4frame.h@, which can be 16 or 32 bits; AFAIK GHC does not run on archs where it is 16-bit, so there's a compile-time check for it.
  , blockChecksumFlag   :: BlockChecksum
  }

-- See comment on `dictID`.
$(if (4) /= (4 :: Int)
{-# LINE 156 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    then error "sizeof(unsigned) is not 4 (32-bits), the code is not written for this"
    else pure []
 )

instance Storable FrameInfo where
  sizeOf _ = (32)
{-# LINE 162 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  alignment _ = 8
{-# LINE 163 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  peek p = do
    blockSizeID <- (\hsc_ptr -> peekByteOff hsc_ptr 0) p
{-# LINE 165 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    blockMode <- (\hsc_ptr -> peekByteOff hsc_ptr 4) p
{-# LINE 166 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    contentChecksumFlag <- (\hsc_ptr -> peekByteOff hsc_ptr 8) p
{-# LINE 167 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    frameType <- (\hsc_ptr -> peekByteOff hsc_ptr 12) p
{-# LINE 168 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    contentSize <- (\hsc_ptr -> peekByteOff hsc_ptr 16) p
{-# LINE 169 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    dictID <- (\hsc_ptr -> peekByteOff hsc_ptr 24) p
{-# LINE 170 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    blockChecksumFlag <- (\hsc_ptr -> peekByteOff hsc_ptr 28) p
{-# LINE 171 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    return $ FrameInfo
      { blockSizeID
      , blockMode
      , contentChecksumFlag
      , frameType
      , contentSize
      , dictID
      , blockChecksumFlag
      }
  poke p frameInfo = do
    (\hsc_ptr -> pokeByteOff hsc_ptr 0) p $ blockSizeID frameInfo
{-# LINE 182 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 4) p $ blockMode frameInfo
{-# LINE 183 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 8) p $ contentChecksumFlag frameInfo
{-# LINE 184 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 12) p $ frameType frameInfo
{-# LINE 185 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 16) p $ contentSize frameInfo
{-# LINE 186 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    -- These were reserved fields once; versions of `lz4frame.h` older
    -- than v1.8.0 will not have them.
    (\hsc_ptr -> pokeByteOff hsc_ptr 24) p $ dictID frameInfo
{-# LINE 189 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 28) p $ blockChecksumFlag frameInfo
{-# LINE 190 "src/Codec/Compression/LZ4/CTypes.hsc" #-}


data Preferences = Preferences
  { frameInfo        :: FrameInfo
  , compressionLevel :: Int
  , autoFlush        :: Bool
  , favorDecSpeed    :: Bool
  }

instance Storable Preferences where
  sizeOf _ = (56)
{-# LINE 201 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  alignment _ = 8
{-# LINE 202 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
  peek p = do
    frameInfo <- (\hsc_ptr -> peekByteOff hsc_ptr 0) p
{-# LINE 204 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    compressionLevel <- (\hsc_ptr -> peekByteOff hsc_ptr 32) p
{-# LINE 205 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    autoFlush <- (\hsc_ptr -> peekByteOff hsc_ptr 36) p
{-# LINE 206 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    favorDecSpeed <- (\hsc_ptr -> peekByteOff hsc_ptr 40) p
{-# LINE 207 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    return $ Preferences
      { frameInfo
      , compressionLevel
      , autoFlush
      , favorDecSpeed
      }
  poke p preferences = do
    fillBytes p 0 (56) -- set reserved fields to 0 as lz4frame.h requires
{-# LINE 215 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 0) p $ frameInfo preferences
{-# LINE 216 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 32) p $ compressionLevel preferences
{-# LINE 217 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 36) p $ autoFlush preferences
{-# LINE 218 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 40) p $ favorDecSpeed preferences -- since lz4 v1.8.2
{-# LINE 219 "src/Codec/Compression/LZ4/CTypes.hsc" #-}
    -- reserved uint field here, see lz4frame.h
    -- reserved uint field here, see lz4frame.h
    -- reserved uint field here, see lz4frame.h


data LZ4F_cctx
data LZ4F_dctx


lz4FrameTypesTable :: Map C.TypeSpecifier TH.TypeQ
lz4FrameTypesTable = Map.fromList
  [ (C.TypeName "LZ4F_cctx", [t| LZ4F_cctx |])
  , (C.TypeName "LZ4F_dctx", [t| LZ4F_dctx |])
  , (C.TypeName "LZ4F_blockSizeID_t", [t| BlockSizeID |])
  , (C.TypeName "LZ4F_blockMode_t", [t| BlockMode |])
  , (C.TypeName "LZ4F_contentChecksum_t", [t| ContentChecksum |])
  , (C.TypeName "LZ4F_blockChecksum_t", [t| BlockChecksum |])
  , (C.TypeName "LZ4F_frameInfo_t", [t| FrameInfo |])
  , (C.TypeName "LZ4F_frameType_t", [t| FrameType |])
  , (C.TypeName "LZ4F_preferences_t", [t| Preferences |])
  ]