{-# LANGUAGE OverloadedStrings #-} -- ---------------------------------------------------------------------------- {- | Normalization and validation for integer. -} -- ---------------------------------------------------------------------------- module Hunt.Index.Schema.Normalize.Int ( normalizeToText, denormalizeFromText , normalizeToInt, denormalizeFromInt , isInt, integer ) where import Data.Text (Text) import qualified Data.Text as T import Control.Applicative hiding ((<|>)) import Hunt.Common.BasicTypes import Text.ParserCombinators.Parsec -- ------------------------------------------------------------ -- Normalize Int to actual Int -- ------------------------------------------------------------ -- | Normalize an integer to an 'Int'. normalizeToInt :: Text -> Int normalizeToInt = getInt -- | Denormalize an integer. denormalizeFromInt :: Int -> Text denormalizeFromInt = T.pack . show -- ------------------------------------------------------------ -- Normalize Int as Text -- ------------------------------------------------------------ -- | Normalize a /valid/ integer to a 'Text' representation preserving ordering. normalizeToText' :: Word -> Word normalizeToText' i = T.concat [pfx, zeros, nr] where (pfx,nr) = if T.take 1 i == "-" then ("0", T.drop 1 i) else ("1", i) elems = 20 - T.length nr zeros = T.replicate elems "0" -- | Normalize an integer to a 'Text' representation preserving ordering. normalizeToText :: Text -> Text normalizeToText t = if isInt t then normalizeToText' t else error "normalizeToText: invalid input" -- | Denormalize a value transformed with 'normalize'. denormalizeFromText :: Text -> Text denormalizeFromText i = sign raw where sign = if T.take 1 i == "1" then id else ('-' `T.cons`) raw = T.dropWhile (== '0') $ T.drop 1 i -- ------------------------------------------------------------ -- Validate int -- ------------------------------------------------------------ -- | Parse a /valid/ integer. -- -- /Note/: This will fail on invalid integers. getInt :: Text -> Int getInt int = case parse integer "" $ T.unpack int of Right pint -> pint _ -> error "getInt: invalid input" -- | Validate if the text represents a valid integer. -- Needs to be within 'Int' range. isInt :: Text -> Bool isInt int = case parse integer "" $ T.unpack int of Right pint -> int == (T.pack . show $ pint) _ -> False -- | Parse a simple integer representation. integer :: Parser Int integer = rd <$> (plus <|> minus <|> number) where rd = read :: String -> Int plus = char '+' *> number minus = (:) <$> char '-' <*> number number = many1 digit -- ------------------------------------------------------------