    -- Copyright (c) 2016-present, Facebook, Inc.
    -- All rights reserved.
    --
    -- This source code is licensed under the BSD-style license found in
    -- the LICENSE file in the root directory of this source tree. An
    -- additional grant of patent rights can be found in the PATENTS file
    -- in the same directory.

    -- |
    -- Module      : Codec.Compression.Zstd.Base
    -- Copyright   : (c) 2016-present, Facebook, Inc. All rights reserved.
    --
    -- License     : BSD3
    -- Maintainer  : bryano@fb.com
    -- Stability   : experimental
    -- Portability : GHC
    --
    -- Mid-level bindings to the native zstd compression library.  These
    -- bindings provide a little more safety and ease of use than the
    -- lowest-level FFI bindings.  Unless you have highly specialized
    -- needs, you should use the streaming or other higher-level APIs
    -- instead.

    module Codec.Compression.Zstd.Base
        (
        -- * One-shot functions
          compress
        , maxCLevel
        , decompress
        , getDecompressedSize

        -- ** Cheaper operations using contexts
        -- *** Compression
        , CCtx
        , withCCtx
        , compressCCtx

        -- *** Decompression
        , DCtx
        , withDCtx
        , decompressDCtx

        -- * Streaming operations
        -- ** Streaming types
        , CStream
        , DStream
        , FFI.Buffer(..)
        , FFI.In
        , FFI.Out

        -- ** Streaming compression
        , cstreamInSize
        , cstreamOutSize
        , createCStream
        , initCStream
        , compressStream
        , endStream

        -- ** Streaming decompression
        , dstreamInSize
        , dstreamOutSize
        , createDStream
        , initDStream
        , decompressStream

        -- * Dictionary compression
        , trainFromBuffer
        , getDictID

        , compressUsingDict
        , decompressUsingDict

        -- ** Pre-digested dictionaries
        -- *** Compression
        , CDict
        , createCDict
        , compressUsingCDict

        -- *** Decompression
        , DDict
        , createDDict
        , decompressUsingDDict
        ) where

    import Codec.Compression.Zstd.Base.Types (CDict(..), DDict(..))
    import Codec.Compression.Zstd.FFI.Types (CCtx, DCtx)
    import Control.Exception.Base (bracket)
    import Data.Word (Word, Word64)
    import Foreign.C.Types (CSize)
    import Foreign.ForeignPtr (ForeignPtr, newForeignPtr, withForeignPtr)
    import Foreign.Ptr (Ptr, castPtr)
    import qualified Codec.Compression.Zstd.FFI as FFI

    -- | Compress bytes from source buffer into destination buffer.
    -- The destination buffer must be already allocated.
    --
    -- Returns the number of bytes written into destination buffer, or an
    -- error description if it fails.
    compress :: Ptr dst         -- ^ Destination buffer.
             -> Int             -- ^ Capacity of destination buffer.
             -> Ptr src         -- ^ Source buffer.
             -> Int             -- ^ Size of source buffer.
             -> Int             -- ^ Compression level.
             -> IO (Either String Int)
    compress :: forall dst src.
    Ptr dst -> Int -> Ptr src -> Int -> Int -> IO (Either String Int)
    compress Ptr dst
    dst Int
    dstSize Ptr src
    src Int
    srcSize Int
    level = IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> IO CSize -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $
      Ptr dst -> CSize -> Ptr src -> CSize -> CInt -> IO CSize
    forall dst src.
    Ptr dst -> CSize -> Ptr src -> CSize -> CInt -> IO CSize
    FFI.compress Ptr dst
    dst (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    dstSize) Ptr src
    src (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    srcSize)
                   (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    level)

    -- | The maximum compression level supported by the library.
    maxCLevel :: Int
    maxCLevel :: Int
    maxCLevel = Int -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    FFI.maxCLevel

    -- | Decompress a buffer.  The destination buffer must be already
    -- allocated.
    --
    -- Returns the number of bytes written into destination buffer, or an
    -- error description if it fails.
    decompress :: Ptr dst         -- ^ Destination buffer.
               -> Int             -- ^ Capacity of destination buffer.
               -> Ptr src         -- ^ Source buffer.
               -> Int
               -- ^ Size of compressed input.  This must be exact, so
               -- for example supplying the size of a buffer that is
               -- larger than the compressed input will cause a failure.
               -> IO (Either String Int)
    decompress :: forall dst src.
    Ptr dst -> Int -> Ptr src -> Int -> IO (Either String Int)
    decompress Ptr dst
    dst Int
    dstSize Ptr src
    src Int
    srcSize = IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> IO CSize -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $
      Ptr dst -> CSize -> Ptr src -> CSize -> IO CSize
    forall dst src. Ptr dst -> CSize -> Ptr src -> CSize -> IO CSize
    FFI.decompress Ptr dst
    dst (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    dstSize) Ptr src
    src (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    srcSize)

    -- | Returns the decompressed size of a compressed payload if known.
    --
    -- To discover precisely why a result is not known, follow up with
    -- 'FFI.getFrameParams'.
    getDecompressedSize :: Ptr src
                        -> Int
                        -> IO (Maybe Word64)
    getDecompressedSize :: forall src. Ptr src -> Int -> IO (Maybe Word64)
    getDecompressedSize Ptr src
    src Int
    srcSize = do
      ret <- Ptr src -> CSize -> IO CULLong
    forall src. Ptr src -> CSize -> IO CULLong
    FFI.getDecompressedSize Ptr src
    src (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    srcSize)
      return $! if ret == 0
                then Nothing
                else Just (fromIntegral ret)

    -- | Allocate a compression context, run an action that may reuse the
    -- context as many times as it needs, then free the context.
    withCCtx :: (Ptr CCtx -> IO a) -> IO a
    withCCtx :: forall a. (Ptr CCtx -> IO a) -> IO a
    withCCtx Ptr CCtx -> IO a
    act =
      IO (Ptr CCtx) -> (Ptr CCtx -> IO ()) -> (Ptr CCtx -> IO a) -> IO a
    forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
    bracket (String -> IO (Ptr CCtx) -> IO (Ptr CCtx)
    forall a. String -> IO (Ptr a) -> IO (Ptr a)
    FFI.checkAlloc String
    "withCCtx" IO (Ptr CCtx)
    FFI.createCCtx) Ptr CCtx -> IO ()
    FFI.freeCCtx Ptr CCtx -> IO a
    act

    -- | Compress bytes from source buffer into destination buffer.
    -- The destination buffer must be already allocated.
    --
    -- Returns the number of bytes written into destination buffer, or an
    -- error description if it fails.
    compressCCtx :: Ptr CCtx    -- ^ Compression context.
                 -> Ptr dst     -- ^ Destination buffer.
                 -> Int         -- ^ Capacity of destination buffer.
                 -> Ptr src     -- ^ Source buffer.
                 -> CSize       -- ^ Size of source buffer.
                 -> Int         -- ^ Compression level.
                 -> IO (Either String Int)
    compressCCtx :: forall dst src.
    Ptr CCtx
    -> Ptr dst
    -> Int
    -> Ptr src
    -> CSize
    -> Int
    -> IO (Either String Int)
    compressCCtx Ptr CCtx
    cctx Ptr dst
    dstPtr Int
    dstSize Ptr src
    srcPtr CSize
    srcSize Int
    level = IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> IO CSize -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $
      Ptr CCtx
    -> Ptr dst -> CSize -> Ptr src -> CSize -> CInt -> IO CSize
    forall dst src.
    Ptr CCtx
    -> Ptr dst -> CSize -> Ptr src -> CSize -> CInt -> IO CSize
    FFI.compressCCtx Ptr CCtx
    cctx Ptr dst
    dstPtr (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    dstSize)
                            Ptr src
    srcPtr (CSize -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral CSize
    srcSize)
                            (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    level)

    -- | Allocate a decompression context, run an action that may reuse
    -- the context as many times as it needs, then free the context.
    withDCtx :: (Ptr DCtx -> IO a) -> IO a
    withDCtx :: forall a. (Ptr DCtx -> IO a) -> IO a
    withDCtx Ptr DCtx -> IO a
    act =
      IO (Ptr DCtx) -> (Ptr DCtx -> IO ()) -> (Ptr DCtx -> IO a) -> IO a
    forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
    bracket (String -> IO (Ptr DCtx) -> IO (Ptr DCtx)
    forall a. String -> IO (Ptr a) -> IO (Ptr a)
    FFI.checkAlloc String
    "withDCtx" IO (Ptr DCtx)
    FFI.createDCtx) Ptr DCtx -> IO ()
    FFI.freeDCtx Ptr DCtx -> IO a
    act

    -- | Decompress a buffer.  The destination buffer must be already
    -- allocated.
    --
    -- Returns the number of bytes written into destination buffer, or an
    -- error description if it fails.
    decompressDCtx :: Ptr DCtx        -- ^ Decompression context.
                   -> Ptr dst         -- ^ Destination buffer.
                   -> Int             -- ^ Capacity of destination buffer.
                   -> Ptr src         -- ^ Source buffer.
                   -> Int
                   -- ^ Size of compressed input.  This must be exact, so
                   -- for example supplying the size of a buffer that is
                   -- larger than the compressed input will cause a failure.
                   -> IO (Either String Int)
    decompressDCtx :: forall dst src.
    Ptr DCtx
    -> Ptr dst -> Int -> Ptr src -> Int -> IO (Either String Int)
    decompressDCtx Ptr DCtx
    dctx Ptr dst
    dst Int
    dstSize Ptr src
    src Int
    srcSize = IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> IO CSize -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $
      Ptr DCtx -> Ptr dst -> CSize -> Ptr src -> CSize -> IO CSize
    forall dst src.
    Ptr DCtx -> Ptr dst -> CSize -> Ptr src -> CSize -> IO CSize
    FFI.decompressDCtx Ptr DCtx
    dctx Ptr dst
    dst (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    dstSize) Ptr src
    src (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    srcSize)

    -- | Recommended size for input buffer.
    cstreamInSize :: Int
    cstreamInSize :: Int
    cstreamInSize = CSize -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral CSize
    FFI.cstreamInSize

    -- | Recommended size for output buffer.
    cstreamOutSize :: Int
    cstreamOutSize :: Int
    cstreamOutSize = CSize -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral CSize
    FFI.cstreamOutSize

    -- | A context for streaming compression.
    newtype CStream = CS (ForeignPtr FFI.CStream)

    -- | Create a 'CStream' value.  After use, this will eventually be
    -- freed via a finalizer.
    createCStream :: IO CStream
    createCStream :: IO CStream
    createCStream = do
      cs <- String -> IO (Ptr CStream) -> IO (Ptr CStream)
    forall a. String -> IO (Ptr a) -> IO (Ptr a)
    FFI.checkAlloc String
    "createCStream" IO (Ptr CStream)
    FFI.createCStream
      cfp <- newForeignPtr FFI.p_freeCStream cs
      return (CS cfp)

    -- | Begin a new streaming compression operation.
    initCStream :: CStream
                -> Int              -- ^ Compression level.
                -> IO (Either String ())
    initCStream :: CStream -> Int -> IO (Either String ())
    initCStream (CS ForeignPtr CStream
    cfp) Int
    level =
      (Either String Int -> Either String ())
    -> IO (Either String Int) -> IO (Either String ())
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ((Int -> ()) -> Either String Int -> Either String ()
    forall a b. (a -> b) -> Either String a -> Either String b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (() -> Int -> ()
    forall a b. a -> b -> a
    const ())) (IO (Either String Int) -> IO (Either String ()))
    -> IO (Either String Int) -> IO (Either String ())
    forall a b. (a -> b) -> a -> b
    $ IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> IO CSize -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $ ForeignPtr CStream -> (Ptr CStream -> IO CSize) -> IO CSize
    forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
    withForeignPtr ForeignPtr CStream
    cfp ((Ptr CStream -> IO CSize) -> IO CSize)
    -> (Ptr CStream -> IO CSize) -> IO CSize
    forall a b. (a -> b) -> a -> b
    $ \Ptr CStream
    cs ->
        Ptr CStream -> CInt -> IO CSize
    FFI.initCStream Ptr CStream
    cs (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    level)

    -- | Consume part or all of an input.
    compressStream :: CStream -> Ptr (FFI.Buffer FFI.Out) -> Ptr (FFI.Buffer FFI.In)
                   -> IO (Either String Int)
    compressStream :: CStream
    -> Ptr (Buffer Out) -> Ptr (Buffer In) -> IO (Either String Int)
    compressStream (CS ForeignPtr CStream
    cfp) Ptr (Buffer Out)
    bi Ptr (Buffer In)
    bo = IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> IO CSize -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $
      ForeignPtr CStream -> (Ptr CStream -> IO CSize) -> IO CSize
    forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
    withForeignPtr ForeignPtr CStream
    cfp ((Ptr CStream -> IO CSize) -> IO CSize)
    -> (Ptr CStream -> IO CSize) -> IO CSize
    forall a b. (a -> b) -> a -> b
    $ \Ptr CStream
    cs ->
        Ptr CStream -> Ptr (Buffer Out) -> Ptr (Buffer In) -> IO CSize
    FFI.compressStream Ptr CStream
    cs Ptr (Buffer Out)
    bi Ptr (Buffer In)
    bo

    -- | End a compression stream. This performs a flush and writes a
    -- frame epilogue.
    endStream :: CStream -> Ptr (FFI.Buffer FFI.Out) -> IO (Either String Int)
    endStream :: CStream -> Ptr (Buffer Out) -> IO (Either String Int)
    endStream (CS ForeignPtr CStream
    cfp) Ptr (Buffer Out)
    bo = IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> IO CSize -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $
      ForeignPtr CStream -> (Ptr CStream -> IO CSize) -> IO CSize
    forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
    withForeignPtr ForeignPtr CStream
    cfp ((Ptr CStream -> IO CSize) -> IO CSize)
    -> (Ptr CStream -> IO CSize) -> IO CSize
    forall a b. (a -> b) -> a -> b
    $ \Ptr CStream
    cs ->
        Ptr CStream -> Ptr (Buffer Out) -> IO CSize
    FFI.endStream Ptr CStream
    cs Ptr (Buffer Out)
    bo

    -- | Recommended size for input buffer.
    dstreamInSize :: Int
    dstreamInSize :: Int
    dstreamInSize = CSize -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral CSize
    FFI.dstreamInSize

    -- | Recommended size for output buffer.
    dstreamOutSize :: Int
    dstreamOutSize :: Int
    dstreamOutSize = CSize -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral CSize
    FFI.dstreamOutSize

    -- | A context for streaming decompression.
    newtype DStream = DS (ForeignPtr FFI.DStream)

    -- | Create a streaming decompression context.  After use, this will
    -- eventually be freed via a finalizer.
    createDStream :: IO DStream
    createDStream :: IO DStream
    createDStream = do
      ds <- String -> IO (Ptr DStream) -> IO (Ptr DStream)
    forall a. String -> IO (Ptr a) -> IO (Ptr a)
    FFI.checkAlloc String
    "createDStream" IO (Ptr DStream)
    FFI.createDStream
      dfp <- newForeignPtr FFI.p_freeDStream ds
      return (DS dfp)

    -- | Begin a new streaming decompression operation.
    initDStream :: DStream
                -> IO (Either String ())
    initDStream :: DStream -> IO (Either String ())
    initDStream (DS ForeignPtr DStream
    dfp) =
      (Either String Int -> Either String ())
    -> IO (Either String Int) -> IO (Either String ())
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ((Int -> ()) -> Either String Int -> Either String ()
    forall a b. (a -> b) -> Either String a -> Either String b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (() -> Int -> ()
    forall a b. a -> b -> a
    const ())) (IO (Either String Int) -> IO (Either String ()))
    -> IO (Either String Int) -> IO (Either String ())
    forall a b. (a -> b) -> a -> b
    $ IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> IO CSize -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $ ForeignPtr DStream -> (Ptr DStream -> IO CSize) -> IO CSize
    forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
    withForeignPtr ForeignPtr DStream
    dfp Ptr DStream -> IO CSize
    FFI.initDStream

    -- | Consume part or all of an input.
    decompressStream :: DStream -> Ptr (FFI.Buffer FFI.Out)
                     -> Ptr (FFI.Buffer FFI.In) -> IO (Either String Int)
    decompressStream :: DStream
    -> Ptr (Buffer Out) -> Ptr (Buffer In) -> IO (Either String Int)
    decompressStream (DS ForeignPtr DStream
    dfp) Ptr (Buffer Out)
    bi Ptr (Buffer In)
    bo = IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> IO CSize -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $
      ForeignPtr DStream -> (Ptr DStream -> IO CSize) -> IO CSize
    forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
    withForeignPtr ForeignPtr DStream
    dfp ((Ptr DStream -> IO CSize) -> IO CSize)
    -> (Ptr DStream -> IO CSize) -> IO CSize
    forall a b. (a -> b) -> a -> b
    $ \Ptr DStream
    ds ->
        Ptr DStream -> Ptr (Buffer Out) -> Ptr (Buffer In) -> IO CSize
    FFI.decompressStream Ptr DStream
    ds Ptr (Buffer Out)
    bi Ptr (Buffer In)
    bo

    -- | Train a dictionary from a collection of samples.
    -- Returns the number size of the resulting dictionary.
    trainFromBuffer :: Ptr dict
                    -- ^ Preallocated dictionary buffer.
                    -> Int
                    -- ^ Capacity of dictionary buffer.
                    -> Ptr samples
                    -- ^ Concatenated samples.
                    -> Ptr Int
                    -- ^ Array of sizes of samples.
                    -> Int
                    -- ^ Number of samples.
                    -> IO (Either String Int)
    trainFromBuffer :: forall dict samples.
    Ptr dict
    -> Int -> Ptr samples -> Ptr Int -> Int -> IO (Either String Int)
    trainFromBuffer Ptr dict
    dictPtr Int
    dictSize Ptr samples
    sampPtr Ptr Int
    sampSizes Int
    sampCount = IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> IO CSize -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $
      Ptr dict -> CSize -> Ptr samples -> Ptr CSize -> CUInt -> IO CSize
    forall dict samples.
    Ptr dict -> CSize -> Ptr samples -> Ptr CSize -> CUInt -> IO CSize
    FFI.trainFromBuffer Ptr dict
    dictPtr (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    dictSize)
                          Ptr samples
    sampPtr (Ptr Int -> Ptr CSize
    forall a b. Ptr a -> Ptr b
    castPtr Ptr Int
    sampSizes) (Int -> CUInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    sampCount)

    -- | Return the identifier for the given dictionary, or 'Nothing' if
    -- not a valid dictionary.
    getDictID :: Ptr dict -> Int -> IO (Maybe Word)
    getDictID :: forall dict. Ptr dict -> Int -> IO (Maybe Word)
    getDictID Ptr dict
    ptr Int
    size = do
      n <- Ptr dict -> CSize -> IO CUInt
    forall dict. Ptr dict -> CSize -> IO CUInt
    FFI.getDictID Ptr dict
    ptr (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    size)
      return $! if n == 0
                then Nothing
                else Just (fromIntegral n)

    -- | Compress bytes from source buffer into destination buffer.
    -- The destination buffer must be already allocated.
    --
    -- Returns the number of bytes written into destination buffer, or an
    -- error description if it fails.
    compressUsingDict :: Ptr CCtx
                      -> Ptr dst         -- ^ Destination buffer.
                      -> Int             -- ^ Capacity of destination buffer.
                      -> Ptr src         -- ^ Source buffer.
                      -> Int             -- ^ Size of source buffer.
                      -> Ptr dict        -- ^ Dictionary.
                      -> Int             -- ^ Size of dictionary.
                      -> Int             -- ^ Compression level.
                      -> IO (Either String Int)
    compressUsingDict :: forall dst src dict.
    Ptr CCtx
    -> Ptr dst
    -> Int
    -> Ptr src
    -> Int
    -> Ptr dict
    -> Int
    -> Int
    -> IO (Either String Int)
    compressUsingDict Ptr CCtx
    ctx Ptr dst
    dst Int
    dstSize Ptr src
    src Int
    srcSize Ptr dict
    dict Int
    dictSize Int
    level = IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> IO CSize -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $
      Ptr CCtx
    -> Ptr dst
    -> CSize
    -> Ptr src
    -> CSize
    -> Ptr dict
    -> CSize
    -> CInt
    -> IO CSize
    forall dst src dict.
    Ptr CCtx
    -> Ptr dst
    -> CSize
    -> Ptr src
    -> CSize
    -> Ptr dict
    -> CSize
    -> CInt
    -> IO CSize
    FFI.compressUsingDict Ptr CCtx
    ctx Ptr dst
    dst (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    dstSize)
        Ptr src
    src (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    srcSize) Ptr dict
    dict (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    dictSize) (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    level)

    -- | Decompress a buffer.  The destination buffer must be already
    -- allocated.
    --
    -- Returns the number of bytes written into destination buffer, or an
    -- error description if it fails.
    decompressUsingDict :: Ptr DCtx
                        -> Ptr dst         -- ^ Destination buffer.
                        -> Int             -- ^ Capacity of destination buffer.
                        -> Ptr src         -- ^ Source buffer.
                        -> Int
                        -- ^ Size of compressed input.  This must be exact, so
                        -- for example supplying the size of a buffer that is
                        -- larger than the compressed input will cause a failure.
                        -> Ptr dict        -- ^ Dictionary.
                        -> Int             -- ^ Size of dictionary.
                        -> IO (Either String Int)
    decompressUsingDict :: forall dst src dict.
    Ptr DCtx
    -> Ptr dst
    -> Int
    -> Ptr src
    -> Int
    -> Ptr dict
    -> Int
    -> IO (Either String Int)
    decompressUsingDict Ptr DCtx
    ctx Ptr dst
    dst Int
    dstSize Ptr src
    src Int
    srcSize Ptr dict
    dict Int
    dictSize = IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> IO CSize -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $
      Ptr DCtx
    -> Ptr dst
    -> CSize
    -> Ptr src
    -> CSize
    -> Ptr dict
    -> CSize
    -> IO CSize
    forall dst src dict.
    Ptr DCtx
    -> Ptr dst
    -> CSize
    -> Ptr src
    -> CSize
    -> Ptr dict
    -> CSize
    -> IO CSize
    FFI.decompressUsingDict Ptr DCtx
    ctx Ptr dst
    dst (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    dstSize)
        Ptr src
    src (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    srcSize) Ptr dict
    dict (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    dictSize)

    -- | Create a pre-digested compression dictionary.  After use, this
    -- will eventually be freed via a finalizer.
    createCDict :: Ptr dict
                -- ^ Dictionary.
                -> Int
                -- ^ Size of dictionary.
                -> Int
                -- ^ Compression level.
                -> IO CDict
    createCDict :: forall dict. Ptr dict -> Int -> Int -> IO CDict
    createCDict Ptr dict
    dict Int
    size Int
    level = do
      cd <- String -> IO (Ptr CDict) -> IO (Ptr CDict)
    forall a. String -> IO (Ptr a) -> IO (Ptr a)
    FFI.checkAlloc String
    "createCDict" (IO (Ptr CDict) -> IO (Ptr CDict))
    -> IO (Ptr CDict) -> IO (Ptr CDict)
    forall a b. (a -> b) -> a -> b
    $
            Ptr dict -> CSize -> CInt -> IO (Ptr CDict)
    forall dict. Ptr dict -> CSize -> CInt -> IO (Ptr CDict)
    FFI.createCDict Ptr dict
    dict (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    size) (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    level)
      fp <- newForeignPtr FFI.p_freeCDict cd
      return (CD fp)

    -- | Compress bytes from source buffer into destination buffer, using
    -- a pre-digested dictionary.  The destination buffer must be already
    -- allocated.
    --
    -- Returns the number of bytes written into destination buffer, or an
    -- error description if it fails.
    compressUsingCDict
        :: Ptr CCtx    -- ^ Compression context.
        -> Ptr dst     -- ^ Destination buffer.
        -> Int         -- ^ Capacity of destination buffer.
        -> Ptr src     -- ^ Source buffer.
        -> Int         -- ^ Size of source buffer.
        -> CDict       -- ^ Dictionary.
        -> IO (Either String Int)
    compressUsingCDict :: forall dst src.
    Ptr CCtx
    -> Ptr dst
    -> Int
    -> Ptr src
    -> Int
    -> CDict
    -> IO (Either String Int)
    compressUsingCDict Ptr CCtx
    ctx Ptr dst
    dst Int
    dstSize Ptr src
    src Int
    srcSize (CD ForeignPtr CDict
    fp) =
      IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> ((Ptr CDict -> IO CSize) -> IO CSize)
    -> (Ptr CDict -> IO CSize)
    -> IO (Either String Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ForeignPtr CDict -> (Ptr CDict -> IO CSize) -> IO CSize
    forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
    withForeignPtr ForeignPtr CDict
    fp ((Ptr CDict -> IO CSize) -> IO (Either String Int))
    -> (Ptr CDict -> IO CSize) -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $ \ Ptr CDict
    dict ->
      Ptr CCtx
    -> Ptr dst -> CSize -> Ptr src -> CSize -> Ptr CDict -> IO CSize
    forall dst src.
    Ptr CCtx
    -> Ptr dst -> CSize -> Ptr src -> CSize -> Ptr CDict -> IO CSize
    FFI.compressUsingCDict Ptr CCtx
    ctx Ptr dst
    dst (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    dstSize)
        Ptr src
    src (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    srcSize) Ptr CDict
    dict

    -- | Create a pre-digested decompression dictionary.  After use, this
    -- will eventually be freed via a finalizer.
    createDDict :: Ptr dict
                -- ^ Dictionary.
                -> Int
                -- ^ Size of dictionary.
                -> IO DDict
    createDDict :: forall dict. Ptr dict -> Int -> IO DDict
    createDDict Ptr dict
    dict Int
    size = do
      cd <- String -> IO (Ptr DDict) -> IO (Ptr DDict)
    forall a. String -> IO (Ptr a) -> IO (Ptr a)
    FFI.checkAlloc String
    "createDDict" (IO (Ptr DDict) -> IO (Ptr DDict))
    -> IO (Ptr DDict) -> IO (Ptr DDict)
    forall a b. (a -> b) -> a -> b
    $
            Ptr dict -> CSize -> IO (Ptr DDict)
    forall dict. Ptr dict -> CSize -> IO (Ptr DDict)
    FFI.createDDict Ptr dict
    dict (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    size)
      fp <- newForeignPtr FFI.p_freeDDict cd
      return (DD fp)

    -- | Decompress bytes from source buffer into destination buffer,
    -- using a pre-digested dictionary.  The destination buffer must be
    -- already allocated.
    --
    -- Returns the number of bytes written into destination buffer, or an
    -- error description if it fails.
    decompressUsingDDict
        :: Ptr DCtx    -- ^ Compression context.
        -> Ptr dst     -- ^ Destination buffer.
        -> Int         -- ^ Capacity of destination buffer.
        -> Ptr src     -- ^ Source buffer.
        -> Int         -- ^ Size of source buffer.
        -> DDict       -- ^ Dictionary.
        -> IO (Either String Int)
    decompressUsingDDict :: forall dst src.
    Ptr DCtx
    -> Ptr dst
    -> Int
    -> Ptr src
    -> Int
    -> DDict
    -> IO (Either String Int)
    decompressUsingDDict Ptr DCtx
    ctx Ptr dst
    dst Int
    dstSize Ptr src
    src Int
    srcSize (DD ForeignPtr DDict
    fp) =
      IO CSize -> IO (Either String Int)
    checkError (IO CSize -> IO (Either String Int))
    -> ((Ptr DDict -> IO CSize) -> IO CSize)
    -> (Ptr DDict -> IO CSize)
    -> IO (Either String Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ForeignPtr DDict -> (Ptr DDict -> IO CSize) -> IO CSize
    forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
    withForeignPtr ForeignPtr DDict
    fp ((Ptr DDict -> IO CSize) -> IO (Either String Int))
    -> (Ptr DDict -> IO CSize) -> IO (Either String Int)
    forall a b. (a -> b) -> a -> b
    $ \ Ptr DDict
    dict ->
      Ptr DCtx
    -> Ptr dst -> CSize -> Ptr src -> CSize -> Ptr DDict -> IO CSize
    forall dst src.
    Ptr DCtx
    -> Ptr dst -> CSize -> Ptr src -> CSize -> Ptr DDict -> IO CSize
    FFI.decompressUsingDDict Ptr DCtx
    ctx Ptr dst
    dst (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    dstSize)
        Ptr src
    src (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    srcSize) Ptr DDict
    dict

    checkError :: IO CSize -> IO (Either String Int)
    checkError :: IO CSize -> IO (Either String Int)
    checkError IO CSize
    act = do
      ret <- IO CSize
    act
      return $! if FFI.isError ret
                then Left (FFI.getErrorName ret)
                else Right (fromIntegral ret)