{-# LANGUAGE BangPatterns #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} module Arbor.File.Format.Asif.Extract ( formats , list , listLazy , map , vectorBoxed , vectorUnboxed , bitmap ) where import Arbor.File.Format.Asif.Data.Ip import Arbor.File.Format.Asif.Format.Type (Format) import Arbor.File.Format.Asif.Whatever import Control.Lens import Data.Binary.Get import Data.List hiding (map) import Data.Text (Text) import Data.Text.Encoding (decodeUtf8') import Data.Text.Encoding.Error import Prelude hiding (map) import qualified Arbor.File.Format.Asif.ByteString.Lazy as LBS import qualified Data.Binary.Get as G import qualified Data.ByteString.Lazy as LBS import qualified Data.List as L import qualified Data.Map.Strict as M import qualified Data.Vector as V import qualified Data.Vector.Unboxed as VU import qualified HaskellWorks.Data.Network.Ip.Ipv4 as IP4 vectorBoxed :: Get a -> LBS.ByteString -> V.Vector a vectorBoxed g = V.unfoldr step where step !s = case runGetOrFail g s of Left (_, _, _) -> Nothing Right (!rs, _, !k) -> Just (k, rs) vectorUnboxed :: VU.Unbox a => Get a -> LBS.ByteString -> VU.Vector a vectorUnboxed g = VU.unfoldr step where step !s = case runGetOrFail g s of Left (_, _, _) -> Nothing Right (!rs, _, !k) -> Just (k, rs) list :: Get a -> LBS.ByteString -> [a] list g = G.runGet go where go = do empty <- G.isEmpty if not empty then (:) <$> g <*> go else return [] listLazy :: Get a -> LBS.ByteString -> [Either String a] listLazy g bs = flip L.unfoldr bs $ \acc -> if LBS.null acc then Nothing else case runGetOrFail g acc of Left (_, _, err) -> Just (Left err, LBS.empty) Right (bs', _, a) -> Just (Right a, bs') map :: (Ord a) => LBS.ByteString -> Get a -> LBS.ByteString -> Get b -> M.Map a b map ks kf vs vf = foldr (\(k, v) m -> M.insert k v m) M.empty $ zip keys values where keys = list kf ks values = list vf vs formats :: LBS.ByteString -> [Maybe (Whatever Format)] formats bs = LBS.split 0 bs <&> decodeUtf8' . LBS.toStrict <&> convert where convert :: Either UnicodeException Text -> Maybe (Whatever Format) convert (Left _) = Nothing convert (Right "") = Nothing convert (Right t) = Just (tReadWhatever t) bitmap :: LBS.ByteString -> [IP4.IpAddress] bitmap lbs = zip [0..] (G.runGet G.getWord64le <$> LBS.chunkBy 8 lbs) >>= \(idx, w64) -> word64ToIpList idx w64 [] <&> word32ToIpv4