------------------------------------------------------------------------
-- |
-- Module      :  Data.BinEmbed
-- Copyright   :  Claude Heiland-Allen 2010
-- Maintainer  :  claude@mathr.co.uk
--
-- Support code used by the output of @binembed --output-hs=@.
--
-- For example, given @MyData.binembed@ listing some files, you might
-- get at the contents embedded into your executable using:
--
-- > import MyData   -- which re-exports this module
-- > main = do
-- >   myData' <- unBinEmbed myData
-- >   ...
--
-- See the 'binembed-example' package for a more detailed example.

module Data.BinEmbed
  ( Node(File, Dir)
  , unBinEmbed
  , unBinEmbedFile
  ) where

import Prelude hiding (sequence)

import Foreign.Ptr (Ptr, castPtr, minusPtr)
import Data.ByteString (ByteString)
import Data.ByteString.Unsafe (unsafePackCStringLen)
import Data.Foldable (Foldable, foldMap)
import Data.Traversable (Traversable, traverse, sequence)
import Data.Map (Map)

-- | A directory tree
data Node a
  = File a                     -- ^ A file has contents.
  | Dir (Map String (Node a))  -- ^ A directory has named @Node@s.
  deriving (Show, Read, Eq, Ord)

instance Functor Node where
  fmap f (File a) = File (           f  a)
  fmap f (Dir  a) = Dir  (fmap (fmap f) a)

instance Foldable Node where
  foldMap f (File a) =                  f  a
  foldMap f (Dir  a) = foldMap (foldMap f) a

instance Traversable Node where
  traverse f (File a) = File `fmap`                    f  a
  traverse f (Dir  a) = Dir  `fmap` traverse (traverse f) a

-- | Unpack embedded data.
unBinEmbed :: Node (IO ByteString) -> IO (Node ByteString)
unBinEmbed = sequence

-- | Repack the contents between two pointers.  Your code probably
--   doesn't need to call this, but it's needed in generated code.
{-   The usage in the code output by @binembed --output-hs=@ is safe,
--   because the embedded file data is in a .rodata section (ie, it is
--   immutable).
-}
unBinEmbedFile :: Ptr () -> Ptr () -> IO ByteString
unBinEmbedFile s e = unsafePackCStringLen (castPtr s, e `minusPtr` s)