include-file (empty) → 0.1.0.0
raw patch · 6 files changed
+220/−0 lines, 6 filesdep +basedep +bytestringdep +criterionbuild-type:Customsetup-changed
Dependencies added: base, bytestring, criterion, include-file, template-haskell
Files
- Development/IncludeFile.hs +91/−0
- LICENSE +30/−0
- Setup.hs +19/−0
- bench/Main.hs +14/−0
- include-file.cabal +46/−0
- test/Main.hs +20/−0
+ Development/IncludeFile.hs view
@@ -0,0 +1,91 @@++-- | Inclusion of files in source code via Template Haskell.+--+-- When distributing executables, sometimes it is required to attach some other resources in+-- files. Using 'includeFileInSource' you avoid this problem by including those files inside+-- the executable at compile time.+--+-- = Example+--+-- A quick example. I want to include a small image (@foo.png@) in the executable. I would do:+--+-- > {-# LANGUAGE TemplateHaskell #-}+-- >+-- > import Development.IncludeFile+-- >+-- > $(includeFileInSource "foo.png" "myImage")+-- >+--+-- This defines the @myImage@ value with type 'S.ByteString' and with the content of the file @foo.png@.+--+-- = Using 'includeFileInSource'+--+-- The following entities must be in scope when calling 'includeFileInSource':+--+-- * A @ByteString@ type.+-- * A @Word8@ type, instance of the 'Num' class (at least with the 'fromInteger' method implemented).+-- * A @pack :: [Word8] -> ByteString@ function.+--+-- This module re-export these for convenience, but you can use your own types (for example, using+-- /lazy/ bytestrings instead of /strict/ bytestrings).+--+-- = Using lazy bytestrings+--+-- To use lazy bytestrings, instead of importing this full module, import it like this:+--+-- > import Data.ByteString.Lazy (ByteString,pack)+-- > import Development.IncludeFile (includeFileInSource,Word8)+--+-- Needless to say, if you have already imported any of those entities, you don't have to do it again.+--+-- = Performance impact+--+-- Benchmarks confirm that it is /much/ faster to use an included bytestring than reading it from a file.+--+-- > benchmarking include-file+-- > time 1.814 ns (1.799 ns .. 1.826 ns)+-- > 1.000 R² (0.999 R² .. 1.000 R²)+-- > mean 1.808 ns (1.797 ns .. 1.819 ns)+-- > std dev 37.48 ps (31.27 ps .. 46.78 ps)+-- > +-- > benchmarking read-file+-- > time 4.869 μs (4.798 μs .. 4.938 μs)+-- > 0.998 R² (0.998 R² .. 0.999 R²)+-- > mean 4.911 μs (4.857 μs .. 4.968 μs)+-- > std dev 178.8 ns (150.1 ns .. 212.5 ns)+--+-- = Large files+--+-- Do not use 'includeFileInSource' with large files. The limit between what /is/ and what is /not/ a large+-- file remains uncertain.+--+module Development.IncludeFile (+ -- * Including files+ includeFileInSource+ -- * Convenient re-exports+ , B.ByteString+ , Word8+ , B.pack+ ) where++import qualified Data.ByteString as B+import Data.Word (Word8)+import Language.Haskell.TH++-- | Define a value of type @ByteString@ (where @ByteString@ is whatever @ByteString@ type is in scope)+-- with the content of a file.+includeFileInSource :: FilePath -- ^ Path to file+ -> String -- ^ Haskell value name+ -> Q [Dec]+includeFileInSource fp n = do+ b <- runIO $ B.readFile fp+ let ws = B.unpack b+ wtype = ConT $ mkName "Word8"+ btype = ConT $ mkName "ByteString"+ return+ [ SigD (mkName n) btype+ , FunD (mkName n) [Clause [] (NormalB $+ AppE (SigE (VarE $ mkName "pack") $ ArrowT `AppT` (ListT `AppT` wtype) `AppT` btype)+ $ ListE $ fmap (LitE . IntegerL . fromIntegral) ws+ ) []]+ ]
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, Daniel Díaz++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Daniel Díaz nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,19 @@++import Distribution.Simple+import System.Random (randomRIO, randomIO)+import qualified Data.ByteString as B+import Control.Monad (replicateM)++main :: IO ()+main = do+ defaultMainWithHooks $+ simpleUserHooks+ { preBuild = \_ _ -> do+ putStr "Generating random file for testing..."+ n <- randomRIO (10,1000)+ ws <- replicateM n randomIO+ let b = B.pack ws+ B.writeFile "test/random" b+ putStrLn " Done."+ return (Nothing,[])+ }
+ bench/Main.hs view
@@ -0,0 +1,14 @@++{-# LANGUAGE TemplateHaskell #-}++import Criterion.Main+import Development.IncludeFile+import qualified Data.ByteString as B++$(includeFileInSource "test/random" "random")++main :: IO ()+main = defaultMain+ [ bench "include-file" $ whnf (const random) (0 :: Int)+ , bench "read-file" $ whnfIO $ B.readFile "test/random"+ ]
+ include-file.cabal view
@@ -0,0 +1,46 @@+name: include-file+version: 0.1.0.0+synopsis: Inclusion of files in executables at compile-time.+description: Inclusion of files in source code via Template Haskell.+ .+ When distributing executables, sometimes it is required+ to attach some other resources in files. Using this library+ (together with the TemplateHaskell extension) you avoid this+ problem by including those files inside the executable at+ compile time.+license: BSD3+license-file: LICENSE+author: Daniel Díaz+maintainer: dhelta.diaz@gmail.com+category: Development+build-type: Custom+cabal-version: >=1.10++library+ exposed-modules: Development.IncludeFile+ build-depends: base == 4.*+ , bytestring+ , template-haskell+ default-language: Haskell2010+ ghc-options: -Wall++test-suite include-file-test+ default-language: Haskell2010+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Main.hs+ build-depends: base == 4.*+ , include-file+ , bytestring+ ghc-options: -fforce-recomp++benchmark include-file-bench+ default-language: Haskell2010+ type: exitcode-stdio-1.0+ hs-source-dirs: bench+ main-is: Main.hs+ build-depends: base == 4.*+ , include-file+ , bytestring+ , criterion+ ghc-options: -fforce-recomp -O2 -Wall
+ test/Main.hs view
@@ -0,0 +1,20 @@++{-# LANGUAGE TemplateHaskell #-}++import System.Exit (exitSuccess, exitFailure)+import Development.IncludeFile+import qualified Data.ByteString as B++$(includeFileInSource "test/random" "test")++main :: IO ()+main = do+ b <- B.readFile "test/random"+ if b == test+ then exitSuccess+ else do putStrLn "Fail: inputs differ."+ putStrLn "Original:"+ print $ B.unpack b+ putStrLn "Included:"+ print $ B.unpack test+ exitFailure