module Data.JsonRpc.Id (Id(..), numberId) where
import Control.Applicative (Applicative, pure)
import Control.Monad (MonadPlus, guard)
import Data.Text (Text)
import Data.Scientific (Scientific, toDecimalDigits)
{-
-- citation from http://www.jsonrpc.org/specification
--
-- An identifier established by the Client that MUST contain
-- a String, Number, or NULL value if included.
-- If it is not included it is assumed to be a notification.
-- The value SHOULD normally not be Null [1]
-- and Numbers SHOULD NOT contain fractional parts [2]
--
-- [1] The use of Null as a value for the id member in
-- a Request object is discouraged, because this specification
-- uses a value of Null for Responses with an unknown id.
-- Also, because JSON-RPC 1.0 uses an id value of Null
-- for Notifications this could cause confusion in handling.
-- [2] Fractional parts may be problematic,
-- since many decimal fractions cannot be
-- represented exactly as binary fractions.
-}
data Id
= StringId !Text
| NumberId !Integer
deriving (Eq, Ord, Show, Read)
numberId :: (MonadPlus m, Applicative m) => Scientific -> m Id
numberId sci = do
let (ds, e) = toDecimalDigits sci
guard $ sci == 0 || null (drop e ds) -- test integral
pure . NumberId $ round sci