module Dingo.Internal.ResourceBundle.Internal ( ResourceBundle , ResourceBundleSet , ResourceDirectory , makeResourceBundle , elemResourceBundleSet , embedDir , findResourceInBundleSet , getResourceBundleContents , resourceBundleSetFromList ) where import Data.ByteString (ByteString) import qualified Data.ByteString.Lazy as BSL import Data.Digest.Pure.SHA (sha256, showDigest) import Data.FileEmbed import qualified Data.Label as L import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as H import Data.Monoid (Monoid(..)) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy.Encoding as TLE -- | Type alias for convience for using 'embedDir'. type ResourceDirectory = [(String, ByteString)] -- | Resource bundle data structure. data ResourceBundle = ResourceBundle { _rbGUID :: Text , _rbDirectory :: HashMap Text ByteString } $(L.mkLabels [''ResourceBundle]) -- | Map of resource bundles. newtype ResourceBundleSet = ResourceBundleSet (HashMap Text ResourceBundle) -- | Make a resource bundle from an embedded directory structure returned by 'embedDir'. makeResourceBundle :: ResourceDirectory -> ResourceBundle makeResourceBundle resourceDirectory = ResourceBundle guid resourceDirectory' where guid = T.pack $ showDigest $ sha256 $ BSL.concat $ map (\(p,c) -> BSL.concat [ TLE.encodeUtf8 $ TL.pack p, BSL.fromChunks [c]]) $ resourceDirectory resourceDirectory' = H.fromList $ map convertFilePath resourceDirectory convertFilePath (p,c) = (T.pack p, c) -- Retrieve resource bundle contents. getResourceBundleContents :: ResourceBundle -> (Text, [(Text,ByteString)]) getResourceBundleContents (ResourceBundle guid directory) = (guid, H.toList directory) -- Create resource bundles structure from a list. resourceBundleSetFromList :: [ResourceBundle] -> ResourceBundleSet resourceBundleSetFromList = ResourceBundleSet . H.fromList . map (\i -> (L.get rbGUID i, i)) -- Find a path within a resource bundle. findResource :: ResourceBundle -> Text -> Maybe ByteString findResource bundle path = H.lookup path $ L.get rbDirectory bundle -- Resource bundle set is a monoid. instance Monoid ResourceBundleSet where mempty = ResourceBundleSet H.empty mappend (ResourceBundleSet a) (ResourceBundleSet b) = ResourceBundleSet (a `mappend` b) -- Find a resource in a set of bundles. findResourceInBundleSet :: Text -> [Text] -> ResourceBundleSet -> Maybe ByteString findResourceInBundleSet bundleId path (ResourceBundleSet resourceBundles) = case H.lookup bundleId resourceBundles of Nothing -> Nothing Just resourceBundle -> findResource resourceBundle path' where path' :: Text path' = T.intercalate "/" path -- Check if a resource bundle exists in a resource bundle set. elemResourceBundleSet :: ResourceBundle -> ResourceBundleSet -> Bool elemResourceBundleSet x (ResourceBundleSet xs) = case H.lookup (L.get rbGUID x) xs of Nothing -> False Just _ -> True