{-# LANGUAGE BangPatterns #-}
module Data.GCStats.Parse
( gcStatsParser
, gcStatsIncr
, ParserState
, initialParserState
) where
import Control.Applicative (optional, (<|>))
import Control.Monad (void)
import qualified Data.Attoparsec.Text as P
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.String
import Data.Text
import qualified Data.Text as T
import GHC.Stats
gcStatsParser :: P.Parser (HashMap Text Double)
gcStatsParser =
let getEntries !m ps = do
m'e <- gcStatsIncr ps
case m'e of
Nothing -> pure m
Just ((k, v), ps') -> getEntries (HashMap.insert k v m) ps'
in getEntries mempty initialParserState
data ParserState
= AtStart
| PastStart
initialParserState :: ParserState
initialParserState = AtStart
gcStatsIncr :: ParserState -> P.Parser (Maybe ((Text, Double), ParserState))
gcStatsIncr ps = case ps of
AtStart -> fmap nextSt gcStatsIncrFirstEntry
PastStart ->
let entryOrEnd = (Just <$> nextEntry) <|> (Nothing <$ gcStatsIncrSkipEnd)
in fmap nextSt entryOrEnd
where
nextSt Nothing = Nothing
nextSt (Just e) = Just (e, PastStart)
gcStatsIncrFirstEntry :: P.Parser (Maybe (Text, Double))
gcStatsIncrFirstEntry = do
P.skipWhile (not . P.isEndOfLine)
P.skipSpace
void $ P.char '['
optional entry
gcStatsIncrSkipEnd :: P.Parser ()
gcStatsIncrSkipEnd = P.skipSpace <* P.char ']'
entry :: P.Parser (Text, Double)
entry = do
_ <- P.char '('
k <- key
_ <- fromString ", "
v <- val
_ <- P.char ')'
pure (k, v)
where
key :: P.Parser Text
key = P.char '"' *> P.takeTill (== '"') <* P.char '"'
val :: P.Parser Double
val = P.char '"' *> P.double <* P.char '"'
nextEntry :: P.Parser (Text, Double)
nextEntry = do
P.skipSpace *> P.char ',' *> P.skipSpace
entry