{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Network.Google.Data.Numeric
( Nat (..)
) where
import Control.Monad
import Data.Aeson
import Data.Data
import Data.Monoid ((<>))
import Data.Scientific
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Lazy as LText
import Data.Text.Lazy.Builder (Builder)
import qualified Data.Text.Lazy.Builder as Build
import qualified Data.Text.Lazy.Builder.Int as Build
import qualified Data.Text.Read as Read
import Numeric.Natural
import Servant.API
newtype Nat = Nat { unNat :: Natural }
deriving (Eq, Ord, Enum, Show, Read, Num, Real, Integral, Data, Typeable)
instance FromJSON Nat where
parseJSON = parseJSON >=> go
where
go n = case floatingOrInteger n of
Left (_ :: Double) -> fail (floatErr n)
Right i
| n < 0 -> fail (negateErr n)
| otherwise -> return . Nat $ fromInteger i
floatErr = mappend "Cannot convert float to Natural: " . show
negateErr = mappend "Cannot convert negative number to Natural: " . show
instance ToJSON Nat where
toJSON = Number . flip scientific 0 . toInteger . unNat
instance ToHttpApiData Nat where
toQueryParam = shortText . Build.decimal
instance FromHttpApiData Nat where
parseQueryParam t =
case Read.decimal t of
Right (x, r) | Text.null r
-> Right x
_ -> Left ("Unable to parse natural from: " <> t)
shortText :: Builder -> Text
shortText = LText.toStrict . Build.toLazyTextWith 32