lz4-hs 0.1.3.0 → 0.1.4.0
raw patch · 6 files changed
+238/−182 lines, 6 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Codec.Lz4.Foreign: lZ4FFreeDecompressionContext :: FinalizerPtr ()
+ Codec.Lz4: compressSz :: Int -> ByteString -> ByteString
+ Codec.Lz4.Foreign: Lz4fBlocklinked :: BlockMode
+ Codec.Lz4.Foreign: Lz4fDefault :: BlockSize
+ Codec.Lz4.Foreign: Lz4fFrame :: FrameType
+ Codec.Lz4.Foreign: Lz4fNoblockchecksum :: BlockChecksum
+ Codec.Lz4.Foreign: Lz4fNocontentchecksum :: ContentChecksum
+ Codec.Lz4.Foreign: data BlockChecksum
+ Codec.Lz4.Foreign: data BlockMode
+ Codec.Lz4.Foreign: data BlockSize
+ Codec.Lz4.Foreign: data ContentChecksum
+ Codec.Lz4.Foreign: data FrameType
+ Codec.Lz4.Foreign: instance GHC.Enum.Enum Codec.Lz4.Foreign.BlockChecksum
+ Codec.Lz4.Foreign: instance GHC.Enum.Enum Codec.Lz4.Foreign.BlockMode
+ Codec.Lz4.Foreign: instance GHC.Enum.Enum Codec.Lz4.Foreign.BlockSize
+ Codec.Lz4.Foreign: instance GHC.Enum.Enum Codec.Lz4.Foreign.ContentChecksum
+ Codec.Lz4.Foreign: instance GHC.Enum.Enum Codec.Lz4.Foreign.FrameType
+ Codec.Lz4.Foreign: type LzPreferencesPtr = ForeignPtr (LzPreferences)
Files
- CHANGELOG.md +4/−0
- lz4-hs.cabal +1/−1
- src/Codec/Lz4.chs +197/−0
- src/Codec/Lz4.hs +0/−169
- src/Codec/Lz4/Foreign.chs +25/−11
- test/Spec.hs +11/−1
CHANGELOG.md view
@@ -1,5 +1,9 @@ # lz4 +## 0.1.4.0++ * Add `compressSz` supporting higher levels of compression for streams+ ## 0.1.3.0 * Add `decompressBufSz` for frames
lz4-hs.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.18 name: lz4-hs-version: 0.1.3.0+version: 0.1.4.0 license: BSD3 license-file: LICENSE copyright: Copyright: (c) 2020 Vanessa McHale
+ src/Codec/Lz4.chs view
@@ -0,0 +1,197 @@+{-# LANGUAGE BangPatterns #-}++-- | The functions in this module throw exceptions on error.+--+-- 'decompress' and 'compress' are fully lazy, i.e. memory efficient.+module Codec.Lz4 ( -- * Functions for working with blocks+ compressBlock+ , decompressBlockSz+ , lZ4MaxInputSize+ , compressBlockHC+ , lZ4HCClevelMax+ -- * Functions for working with frames+ , compress+ , compressSz+ , decompress+ , decompressBufSz+ -- * Version info+ , lZ4VersionNumber+ , lZ4VersionString+ ) where++import Codec.Lz4.Foreign+import Control.Monad (when)+import Control.Monad.ST.Lazy (runST)+import qualified Control.Monad.ST.Lazy as LazyST+import qualified Control.Monad.ST.Lazy.Unsafe as LazyST+import qualified Data.ByteString as BS+import qualified Data.ByteString.Internal as BS+import qualified Data.ByteString.Lazy as BSL+import qualified Data.ByteString.Unsafe as BS+import Foreign.C.String (CString)+import Foreign.C.Types (CInt)+import Foreign.Ptr (castPtr, nullPtr)+import Foreign.ForeignPtr (ForeignPtr, castForeignPtr,+ mallocForeignPtrBytes,+ newForeignPtr, withForeignPtr)+import Foreign.Marshal.Alloc (alloca)+import Foreign.Storable (peek, poke)+import System.IO.Unsafe (unsafePerformIO)++#include <lz4frame.h>++check :: LZ4FErrorCode -> IO ()+check err = when (lZ4FIsError err) $ error (lZ4FGetErrorName err)++-- | Lazily decompress a frame+decompress :: BSL.ByteString -> BSL.ByteString+decompress = decompressBufSz (64 * 1014)++-- | @since 0.1.3.0+decompressBufSz :: Int -- ^ Size of the output buffer+ -> BSL.ByteString+ -> BSL.ByteString+decompressBufSz bufSz bs = runST $ do++ let bss = BSL.toChunks bs++ (ctx, buf) <- LazyST.unsafeIOToST $ do+ (err, preCtx) <- lZ4FCreateDecompressionContext lZ4FGetVersion+ ctx <- castForeignPtr <$> newForeignPtr lZ4FFreeCompressionContext (castPtr preCtx)+ check err+ dstBuf <- mallocForeignPtrBytes bufSz+ pure (ctx, dstBuf)++ BSL.fromChunks <$> loop ctx buf bss++ where loop :: LzDecompressionCtxPtr -> ForeignPtr a -> [BS.ByteString] -> LazyST.ST s [BS.ByteString]+ loop _ _ [] = pure []+ loop ctx buf (b:bs') = do+ (nxt, res) <- stepChunk ctx buf b+ case nxt of+ Nothing -> (res:) <$> loop ctx buf bs'+ Just next -> (res:) <$> loop ctx buf (next:bs')+++ stepChunk :: LzDecompressionCtxPtr -> ForeignPtr a -> BS.ByteString -> LazyST.ST s (Maybe BS.ByteString, BS.ByteString)+ stepChunk !ctx !dst b = LazyST.unsafeIOToST $+ BS.unsafeUseAsCStringLen b $ \(buf, sz) ->+ withForeignPtr dst $ \d ->+ alloca $ \dSzPtr ->+ alloca $ \szPtr -> do+ poke dSzPtr (fromIntegral bufSz)+ poke szPtr (fromIntegral sz)+ res <- lZ4FDecompress ctx d dSzPtr buf szPtr nullPtr+ check res+ bRead <- peek szPtr+ bWritten <- peek dSzPtr+ outBs <- BS.packCStringLen (castPtr d, fromIntegral bWritten)+ let remBs = if fromIntegral bRead == sz+ then Nothing+ else Just (BS.drop (fromIntegral bRead) b)+ pure (remBs, outBs)++-- | Lazily compress a frame.+compress :: BSL.ByteString -> BSL.ByteString+compress = compressSz 0++-- | @since 0.1.4.0+compressSz :: Int -> BSL.ByteString -> BSL.ByteString+compressSz lvl bs = runST $ do++ let bss = BSL.toChunks bs++ (ctx, pref, header) <- initCtx+ rest <- loop ctx pref bss++ pure $ BSL.fromChunks (header:rest)++ where initCtx :: LazyST.ST s (LzCtxPtr, LzPreferencesPtr, BS.ByteString)+ initCtx = LazyST.unsafeIOToST $ do+ (err, preCtx) <- lZ4FCreateCompressionContext lZ4FGetVersion+ ctx <- castForeignPtr <$> newForeignPtr lZ4FFreeCompressionContext (castPtr preCtx)+ check err+ dst <- mallocForeignPtrBytes lZ4FHeaderSizeMax+ pref <- mallocForeignPtrBytes {# sizeof LZ4F_preferences_t #}+ preferencesPtr pref lvl+ header <- withForeignPtr dst $ \d -> do+ res <- lZ4FCompressBegin ctx d lZ4FHeaderSizeMax pref+ check res+ BS.packCStringLen (castPtr d, fromIntegral res)+ pure (ctx, pref, header)++ loop :: LzCtxPtr -> LzPreferencesPtr -> [BS.ByteString] -> LazyST.ST s [BS.ByteString]+ loop ctx pref [] = pure <$> finish ctx pref+ loop ctx pref (b:bs') = (:) <$> update ctx pref b <*> loop ctx pref bs'++ finish :: LzCtxPtr -> LzPreferencesPtr -> LazyST.ST s BS.ByteString+ finish ctx pref = LazyST.unsafeIOToST $ do+ let expectedSz = lZ4FCompressBound 0 pref+ dst <- mallocForeignPtrBytes (fromIntegral expectedSz)+ withForeignPtr dst $ \d -> do+ res <- lZ4FCompressEnd ctx d expectedSz nullPtr+ check res+ BS.packCStringLen (castPtr d, fromIntegral res)++ update :: LzCtxPtr -> LzPreferencesPtr -> BS.ByteString -> LazyST.ST s BS.ByteString+ update !ctx !pref b = LazyST.unsafeIOToST $+ BS.unsafeUseAsCStringLen b $ \(buf, sz) -> do+ let expectedSz = lZ4FCompressBound (fromIntegral sz) pref+ dst <- mallocForeignPtrBytes (fromIntegral expectedSz)+ withForeignPtr dst $ \d -> do+ res <- lZ4FCompressUpdate ctx d expectedSz buf (fromIntegral sz) nullPtr+ check res+ BS.packCStringLen (castPtr d, fromIntegral res)++{-# NOINLINE compressBlock #-}+compressBlock :: BS.ByteString -> BS.ByteString+compressBlock = unsafePerformIO . compressBlockGeneric lZ4CompressDefault++{-# NOINLINE compressBlockHC #-}+-- | @since 0.1.1.0+compressBlockHC :: Int -- ^ Compression level (must be less than 'lZ4HCClevelMax')+ -> BS.ByteString+ -> BS.ByteString+compressBlockHC lvl = unsafePerformIO . compressBlockGeneric (\src dst ssz dsz -> lZ4CompressHC src dst ssz dsz (fromIntegral lvl))++compressBlockGeneric :: (CString -> CString -> CInt -> CInt -> IO CInt) -> BS.ByteString -> IO BS.ByteString+compressBlockGeneric cfun bs =+ BS.unsafeUseAsCStringLen bs $ \(buf, sz) -> do+ let resSz = lZ4CompressBound (fromIntegral sz)+ dst <- mallocForeignPtrBytes (fromIntegral resSz)+ withForeignPtr dst $ \d -> do+ bWritten <- cfun buf d (fromIntegral sz) resSz+ when (bWritten == 0) $ error "Compression error"+ pure $ BS.fromForeignPtr (castForeignPtr dst) 0 (fromIntegral bWritten)++{-# NOINLINE decompressBlockSz #-}+-- | Decompress a block. The size of the uncompressed data must be known.+decompressBlockSz :: BS.ByteString+ -> Int -- ^ Decompressed size+ -> BS.ByteString+decompressBlockSz bs expectedSz = unsafePerformIO $+ BS.unsafeUseAsCStringLen bs $ \(buf, sz) -> do+ dst <- mallocForeignPtrBytes expectedSz+ withForeignPtr dst $ \d -> do+ bWritten <- lZ4DecompressSafe buf d (fromIntegral sz) (fromIntegral expectedSz)+ when (bWritten < 0) $ error "Decompression error"+ pure $ BS.fromForeignPtr (castForeignPtr dst) 0 expectedSz++cint :: Enum a => a -> CInt+cint = fromIntegral . fromEnum++preferencesPtr :: LzPreferencesPtr -> Int -> IO ()+preferencesPtr fp i =+ withForeignPtr fp $ \p -> do++ {# set LZ4F_preferences_t.frameInfo.blockSizeID #} p (cint Lz4fDefault)+ {# set LZ4F_preferences_t.frameInfo.blockMode #} p (cint Lz4fBlocklinked)+ {# set LZ4F_preferences_t.frameInfo.contentChecksumFlag #} p (cint Lz4fNocontentchecksum)+ {# set LZ4F_preferences_t.frameInfo.frameType #} p (cint Lz4fFrame)+ {# set LZ4F_preferences_t.frameInfo.contentSize #} p 0+ {# set LZ4F_preferences_t.frameInfo.dictID #} p 0+ {# set LZ4F_preferences_t.frameInfo.blockChecksumFlag #} p (cint Lz4fNoblockchecksum)++ {# set LZ4F_preferences_t.compressionLevel #} p (fromIntegral i)+ {# set LZ4F_preferences_t.autoFlush #} p 0+ {# set LZ4F_preferences_t.favorDecSpeed #} p 0
− src/Codec/Lz4.hs
@@ -1,169 +0,0 @@-{-# LANGUAGE BangPatterns #-}---- | The functions in this module throw exceptions on error.------ 'decompress' and 'compress' are fully lazy, i.e. memory efficient.-module Codec.Lz4 ( -- * Functions for working with blocks- compressBlock- , decompressBlockSz- , lZ4MaxInputSize- , compressBlockHC- , lZ4HCClevelMax- -- * Functions for working with frames- , compress- , decompress- , decompressBufSz- -- * Version info- , lZ4VersionNumber- , lZ4VersionString- ) where--import Codec.Lz4.Foreign-import Control.Monad (when)-import Control.Monad.ST.Lazy (runST)-import qualified Control.Monad.ST.Lazy as LazyST-import qualified Control.Monad.ST.Lazy.Unsafe as LazyST-import qualified Data.ByteString as BS-import qualified Data.ByteString.Internal as BS-import qualified Data.ByteString.Lazy as BSL-import qualified Data.ByteString.Unsafe as BS-import Foreign.C.String (CString)-import Foreign.C.Types (CInt)-import Foreign.ForeignPtr (ForeignPtr, castForeignPtr,- mallocForeignPtrBytes,- newForeignPtr, withForeignPtr)-import Foreign.Marshal.Alloc (alloca)-import Foreign.Ptr (castPtr, nullPtr)-import Foreign.Storable (peek, poke)-import System.IO.Unsafe (unsafePerformIO)--check :: LZ4FErrorCode -> IO ()-check err = when (lZ4FIsError err) $ error (lZ4FGetErrorName err)---- | Lazily decompress a frame-decompress :: BSL.ByteString -> BSL.ByteString-decompress = decompressBufSz (64 * 1014)---- | @since 0.1.3.0-decompressBufSz :: Int -- ^ Size of the output buffer- -> BSL.ByteString- -> BSL.ByteString-decompressBufSz bufSz bs = runST $ do-- let bss = BSL.toChunks bs-- (ctx, buf) <- LazyST.unsafeIOToST $ do- (err, preCtx) <- lZ4FCreateDecompressionContext lZ4FGetVersion- check err- ctx <- castForeignPtr <$> newForeignPtr lZ4FFreeCompressionContext (castPtr preCtx)- dstBuf <- mallocForeignPtrBytes bufSz- pure (ctx, dstBuf)-- BSL.fromChunks <$> loop ctx buf bss-- where loop :: LzDecompressionCtxPtr -> ForeignPtr a -> [BS.ByteString] -> LazyST.ST s [BS.ByteString]- loop _ _ [] = pure []- loop ctx buf (b:bs') = do- (nxt, res) <- stepChunk ctx buf b- case nxt of- Nothing -> (res:) <$> loop ctx buf bs'- Just next -> (res:) <$> loop ctx buf (next:bs')--- stepChunk :: LzDecompressionCtxPtr -> ForeignPtr a -> BS.ByteString -> LazyST.ST s (Maybe BS.ByteString, BS.ByteString)- stepChunk !ctx !dst b = LazyST.unsafeIOToST $- BS.unsafeUseAsCStringLen b $ \(buf, sz) ->- withForeignPtr dst $ \d ->- alloca $ \dSzPtr ->- alloca $ \szPtr -> do- poke dSzPtr (fromIntegral bufSz)- poke szPtr (fromIntegral sz)- res <- lZ4FDecompress ctx d dSzPtr buf szPtr nullPtr- check res- bRead <- peek szPtr- bWritten <- peek dSzPtr- outBs <- BS.packCStringLen (castPtr d, fromIntegral bWritten)- let remBs = if fromIntegral bRead == sz- then Nothing- else Just (BS.drop (fromIntegral bRead) b)- pure (remBs, outBs)---- | Lazily compress a frame.-compress :: BSL.ByteString -> BSL.ByteString-compress bs = runST $ do-- let bss = BSL.toChunks bs-- (ctx, header) <- initCtx- rest <- loop ctx bss-- pure $ BSL.fromChunks (header:rest)-- where initCtx :: LazyST.ST s (LzCtxPtr, BS.ByteString)- initCtx = LazyST.unsafeIOToST $ do- (err, preCtx) <- lZ4FCreateCompressionContext lZ4FGetVersion- check err- ctx <- castForeignPtr <$> newForeignPtr lZ4FFreeCompressionContext (castPtr preCtx)- dst <- mallocForeignPtrBytes lZ4FHeaderSizeMax- header <- withForeignPtr dst $ \d -> do- res <- lZ4FCompressBegin ctx d lZ4FHeaderSizeMax nullPtr- check res- BS.packCStringLen (castPtr d, fromIntegral res)- pure (ctx, header)-- loop :: LzCtxPtr -> [BS.ByteString] -> LazyST.ST s [BS.ByteString]- loop ctx [] = pure <$> finish ctx- loop ctx (b:bs') = (:) <$> update ctx b <*> loop ctx bs'-- finish :: LzCtxPtr -> LazyST.ST s BS.ByteString- finish ctx = LazyST.unsafeIOToST $ do- let expectedSz = lZ4FCompressBound 0 nullPtr- dst <- mallocForeignPtrBytes (fromIntegral expectedSz)- withForeignPtr dst $ \d -> do- res <- lZ4FCompressEnd ctx d expectedSz nullPtr- check res- BS.packCStringLen (castPtr d, fromIntegral res)-- update :: LzCtxPtr -> BS.ByteString -> LazyST.ST s BS.ByteString- update !ctx b = LazyST.unsafeIOToST $- BS.unsafeUseAsCStringLen b $ \(buf, sz) -> do- let expectedSz = lZ4FCompressBound (fromIntegral sz) nullPtr- dst <- mallocForeignPtrBytes (fromIntegral expectedSz)- withForeignPtr dst $ \d -> do- res <- lZ4FCompressUpdate ctx d expectedSz buf (fromIntegral sz) nullPtr- check res- BS.packCStringLen (castPtr d, fromIntegral res)--{-# NOINLINE compressBlock #-}-compressBlock :: BS.ByteString -> BS.ByteString-compressBlock = unsafePerformIO . compressBlockGeneric lZ4CompressDefault--{-# NOINLINE compressBlockHC #-}--- | @since 0.1.1.0-compressBlockHC :: Int -- ^ Compression level (must be less than 'lZ4HCClevelMax')- -> BS.ByteString- -> BS.ByteString-compressBlockHC lvl = unsafePerformIO . compressBlockGeneric (\src dst ssz dsz -> lZ4CompressHC src dst ssz dsz (fromIntegral lvl))--compressBlockGeneric :: (CString -> CString -> CInt -> CInt -> IO CInt) -> BS.ByteString -> IO BS.ByteString-compressBlockGeneric cfun bs =- BS.unsafeUseAsCStringLen bs $ \(buf, sz) -> do- let resSz = lZ4CompressBound (fromIntegral sz)- dst <- mallocForeignPtrBytes (fromIntegral resSz)- withForeignPtr dst $ \d -> do- bWritten <- cfun buf d (fromIntegral sz) resSz- when (bWritten == 0) $ error "Compression error"- pure $ BS.fromForeignPtr (castForeignPtr dst) 0 (fromIntegral bWritten)--{-# NOINLINE decompressBlockSz #-}--- | Decompress a block. The size of the uncompressed data must be known.-decompressBlockSz :: BS.ByteString- -> Int -- ^ Decompressed size- -> BS.ByteString-decompressBlockSz bs expectedSz = unsafePerformIO $- BS.unsafeUseAsCStringLen bs $ \(buf, sz) -> do- dst <- mallocForeignPtrBytes expectedSz- withForeignPtr dst $ \d -> do- bWritten <- lZ4DecompressSafe buf d (fromIntegral sz) (fromIntegral expectedSz)- when (bWritten < 0) $ error "Decompression error"- pure $ BS.fromForeignPtr (castForeignPtr dst) 0 expectedSz
src/Codec/Lz4/Foreign.chs view
@@ -1,3 +1,5 @@+{-# LANGUAGE CApiFFI #-}+ module Codec.Lz4.Foreign ( -- * Blocks lZ4VersionNumber , lZ4VersionString@@ -16,10 +18,10 @@ , lZ4FCompressUpdate , lZ4FCompressEnd , lZ4FCreateDecompressionContext- , lZ4FFreeDecompressionContext , lZ4FDecompress , lZ4MaxInputSize , lZ4CompressHC+ -- * Macros , lZ4HCClevelMax -- * Types , LZ4FErrorCode@@ -27,6 +29,12 @@ , LzCtxPtr , LzDecompressionCtx , LzDecompressionCtxPtr+ , LzPreferencesPtr+ , BlockMode (Lz4fBlocklinked)+ , BlockSize (Lz4fDefault)+ , ContentChecksum (Lz4fNocontentchecksum)+ , BlockChecksum (Lz4fNoblockchecksum)+ , FrameType (Lz4fFrame) ) where import Data.Coerce (coerce)@@ -40,12 +48,18 @@ #include <lz4frame.h> #include <lz4hc.h> +{# enum LZ4F_blockSizeID_t as BlockSize {underscoreToCase} #}+{# enum LZ4F_blockMode_t as BlockMode {underscoreToCase} #}+{# enum LZ4F_contentChecksum_t as ContentChecksum {underscoreToCase} #}+{# enum LZ4F_blockChecksum_t as BlockChecksum {underscoreToCase} #}+{# enum LZ4F_frameType_t as FrameType {underscoreToCase} #}+ {# fun pure LZ4_versionNumber as ^ {} -> `CInt' #} -- | @since 0.1.1.0 {# fun pure LZ4_versionString as ^ {} -> `String' #} -{# fun LZ4_compress_default as ^ { `CString', `CString', `CInt' , `CInt' } -> `CInt' #}-{# fun LZ4_decompress_safe as ^ { `CString', `CString', `CInt' , `CInt' } -> `CInt' #}+{# fun unsafe LZ4_compress_default as ^ { `CString', `CString', `CInt' , `CInt' } -> `CInt' #}+{# fun unsafe LZ4_decompress_safe as ^ { `CString', `CString', `CInt' , `CInt' } -> `CInt' #} {# fun pure LZ4_compressBound as ^ { `CInt' } -> `CInt' #} @@ -61,16 +75,16 @@ {# pointer *LZ4F_cctx as LzCtxPtr foreign finalizer LZ4F_freeCompressionContext as ^ -> LzCtx #} -{# fun LZ4F_createCompressionContext as ^ { alloca- `Ptr LzCtx' peek*, `CUInt' } -> `LZ4FErrorCode' #}+{# fun unsafe LZ4F_createCompressionContext as ^ { alloca- `Ptr LzCtx' peek*, `CUInt' } -> `LZ4FErrorCode' #} data LzPreferences -{# pointer *LZ4F_preferences_t as LzPreferencesPtr -> LzPreferences #}+{# pointer *LZ4F_preferences_t as LzPreferencesPtr foreign -> LzPreferences #} lZ4FHeaderSizeMax :: Integral a => a lZ4FHeaderSizeMax = {# const LZ4F_HEADER_SIZE_MAX #} -{# fun LZ4F_compressBegin as ^ { `LzCtxPtr', castPtr `Ptr a', coerce `CSize', `LzPreferencesPtr' } -> `CSize' coerce #}+{# fun unsafe LZ4F_compressBegin as ^ { `LzCtxPtr', castPtr `Ptr a', coerce `CSize', `LzPreferencesPtr' } -> `CSize' coerce #} {# fun pure LZ4F_compressBound as ^ { coerce `CSize', `LzPreferencesPtr' } -> `CSize' coerce #} @@ -78,7 +92,7 @@ {# pointer *LZ4F_compressOptions_t as LzCompressOptionsPtr -> LzCompressOptions #} -{# fun LZ4F_compressUpdate as ^+{# fun unsafe LZ4F_compressUpdate as ^ { `LzCtxPtr' , castPtr `Ptr a' , coerce `CSize'@@ -88,20 +102,20 @@ } -> `CSize' coerce #} -{# fun LZ4F_compressEnd as ^+{# fun unsafe LZ4F_compressEnd as ^ { `LzCtxPtr', castPtr `Ptr a', coerce `CSize', `LzCompressOptionsPtr' } -> `CSize' coerce #} data LzDecompressionCtx {# pointer *LZ4F_dctx as LzDecompressionCtxPtr foreign finalizer LZ4F_freeDecompressionContext as ^ -> LzDecompressionCtx #} -{# fun LZ4F_createDecompressionContext as ^ { alloca- `Ptr LzDecompressionCtx' peek*, `CUInt' } -> `LZ4FErrorCode' #}+{# fun unsafe LZ4F_createDecompressionContext as ^ { alloca- `Ptr LzDecompressionCtx' peek*, `CUInt' } -> `LZ4FErrorCode' #} data LzDecompressOptions {# pointer *LZ4F_decompressOptions_t as LzDecompressOptionsPtr -> LzDecompressOptions #} -{# fun LZ4F_decompress as ^+{# fun unsafe LZ4F_decompress as ^ { `LzDecompressionCtxPtr' , castPtr `Ptr a' , castPtr `Ptr CSize'@@ -115,7 +129,7 @@ lZ4MaxInputSize :: Integral a => a lZ4MaxInputSize = {# const LZ4_MAX_INPUT_SIZE #} -{# fun LZ4_compress_HC as ^+{# fun unsafe LZ4_compress_HC as ^ { `CString', `CString', `CInt', `CInt', `CInt' } -> `CInt' #} -- | @since 0.1.1.0
test/Spec.hs view
@@ -6,6 +6,13 @@ import Test.Tasty import Test.Tasty.HUnit +testCompression :: FilePath -> TestTree+testCompression fp = testCase ("Highly compressed frames " ++ fp) $ do+ contents <- BSL.readFile "cbits/lz4.c"+ let sz0 = BSL.length (compressSz 0 contents)+ sz1 = BSL.length (compressSz 6 contents)+ assertBool "higher compression means smaller frames" $ sz1 < sz0+ testRoundtripBlocks :: FilePath -> TestTree testRoundtripBlocks fp = testCase ("Roundtrip " ++ fp) $ do contents <- BS.readFile fp@@ -23,7 +30,7 @@ main = defaultMain $- testGroup "lz4" [testBlocks, testFrames]+ testGroup "lz4" [testBlocks, testFrames, testHC] where testBlocks = testGroup "Block compression"@@ -32,4 +39,7 @@ ] testFrames = testGroup "Frame compression" [ testRoundtripFrames "cbits/lz4.c"+ ]+ testHC = testGroup "Compression levels"+ [ testCompression "cbits/lz4frame.c" ]