module Prometheus.Info (
    Info (..)
,   checkInfo
) where

import Data.Text (Text)
import qualified Data.Text as T

-- | Meta data about a metric including its name and a help string that
-- describes the value that the metric is measuring.
data Info = Info {
    Info -> Text
metricName :: Text
,   Info -> Text
metricHelp :: Text
} deriving (ReadPrec [Info]
ReadPrec Info
Int -> ReadS Info
ReadS [Info]
(Int -> ReadS Info)
-> ReadS [Info] -> ReadPrec Info -> ReadPrec [Info] -> Read Info
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Info]
$creadListPrec :: ReadPrec [Info]
readPrec :: ReadPrec Info
$creadPrec :: ReadPrec Info
readList :: ReadS [Info]
$creadList :: ReadS [Info]
readsPrec :: Int -> ReadS Info
$creadsPrec :: Int -> ReadS Info
Read, Int -> Info -> ShowS
[Info] -> ShowS
Info -> String
(Int -> Info -> ShowS)
-> (Info -> String) -> ([Info] -> ShowS) -> Show Info
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Info] -> ShowS
$cshowList :: [Info] -> ShowS
show :: Info -> String
$cshow :: Info -> String
showsPrec :: Int -> Info -> ShowS
$cshowsPrec :: Int -> Info -> ShowS
Show, Info -> Info -> Bool
(Info -> Info -> Bool) -> (Info -> Info -> Bool) -> Eq Info
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Info -> Info -> Bool
$c/= :: Info -> Info -> Bool
== :: Info -> Info -> Bool
$c== :: Info -> Info -> Bool
Eq, Eq Info
Eq Info
-> (Info -> Info -> Ordering)
-> (Info -> Info -> Bool)
-> (Info -> Info -> Bool)
-> (Info -> Info -> Bool)
-> (Info -> Info -> Bool)
-> (Info -> Info -> Info)
-> (Info -> Info -> Info)
-> Ord Info
Info -> Info -> Bool
Info -> Info -> Ordering
Info -> Info -> Info
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Info -> Info -> Info
$cmin :: Info -> Info -> Info
max :: Info -> Info -> Info
$cmax :: Info -> Info -> Info
>= :: Info -> Info -> Bool
$c>= :: Info -> Info -> Bool
> :: Info -> Info -> Bool
$c> :: Info -> Info -> Bool
<= :: Info -> Info -> Bool
$c<= :: Info -> Info -> Bool
< :: Info -> Info -> Bool
$c< :: Info -> Info -> Bool
compare :: Info -> Info -> Ordering
$ccompare :: Info -> Info -> Ordering
$cp1Ord :: Eq Info
Ord)

checkInfo :: Info -> a -> a
checkInfo :: Info -> a -> a
checkInfo Info
info a
a
    | (Char
x:String
_)       <- Text -> String
T.unpack Text
name, Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Char -> Bool
validStart Char
x     = a
forall a. a
errorInvalid
    | (Char
_:String
xs)      <- Text -> String
T.unpack Text
name, Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Char -> Bool
validRest String
xs = a
forall a. a
errorInvalid
    | (Char
'_':Char
'_':String
_) <- Text -> String
T.unpack Text
name                         = a
forall a. a
errorPrefix
    | []          <- Text -> String
T.unpack Text
name                         = a
forall a. a
errorEmpty
    | Bool
otherwise                                   = a
a
    where
        name :: Text
name = Info -> Text
metricName Info
info

        errorInvalid :: a
errorInvalid = String -> a
forall a. HasCallStack => String -> a
error (String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [
                String
"The metric '", Text -> String
T.unpack Text
name, String
"' contains invalid characters."
            ]

        errorPrefix :: a
errorPrefix = String -> a
forall a. HasCallStack => String -> a
error (String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [
                String
"The metric '", Text -> String
T.unpack Text
name, String
"' cannot start with '__'."
            ]

        errorEmpty :: a
errorEmpty = String -> a
forall a. HasCallStack => String -> a
error String
"Empty metric names are not allowed."

        validStart :: Char -> Bool
validStart Char
c =  (Char
'a' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'z')
                     Bool -> Bool -> Bool
|| (Char
'A' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'Z')
                     Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'_'
                     Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
':'

        validRest :: Char -> Bool
validRest Char
c =  (Char
'a' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'z')
                    Bool -> Bool -> Bool
|| (Char
'A' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'Z')
                    Bool -> Bool -> Bool
|| (Char
'0' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'9')
                    Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'_'
                    Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
':'