json2-0.8.2: src/Data/JSON2/Internal.hs
module Data.JSON2.Internal
( -- * Helpers of check conversion.
ConvResult
, checkBoundsIntegral
, checkBoundsEnum
, checkInfinite
-- , checkRead
, ConvError(ConvError)
, mkError
, mkError'
)
where
import Control.Monad.Error
import Data.Typeable
-- Conversion
type ConvResult a = Either ConvError a
-- | Conversion `Rational` number to `Integral` number with check bounds.
checkBoundsIntegral :: (Typeable a, Bounded a, Integral a)
=> (Rational -> a) -> Rational -> ConvResult a
checkBoundsIntegral f x = do
let res = f x
let min = toRational (asTypeOf minBound res)
let max = toRational (asTypeOf maxBound res)
if x >= min && x <= max
then
return res
else
mkError' ("Value must between: (" ++ show min ++ ", "
++ show max ++ ")") x
-- | Conversion `Rational` number to `Bounded` values with check bounds.
-- checkBoundsEnum (toEnum . round)
checkBoundsEnum :: (Typeable a, Bounded a, Enum a)
=> (Rational -> a) -> Rational -> ConvResult a
checkBoundsEnum f x = do
let x' = fromEnum x
let res = f x
let min = fromEnum (asTypeOf minBound res)
let max = fromEnum (asTypeOf maxBound res)
if x' >= min && x' <= max
then
return res
else
mkError' ("Value must between: (" ++ show min ++ ", "
++ show max ++ ")") x
-- | Conversion `Rational` to `RealFloat` values with check infinity.
checkInfinite :: (Typeable a, RealFloat a)
=> (Rational -> a) -> Rational -> ConvResult a
checkInfinite f x = do
let res = f x
if not (isInfinite res)
then
return res
else
mkError' "Value conveversion to infinity. " x
-- | Read whith check.
checkRead :: (Read a, Typeable a) => (ReadS a) -> String -> ConvResult a
checkRead r s = do
let res = r s
case res of
[(x, "")] -> return x
_ -> mkError' "Read error" s
-- Error Handling
-- | Create conversion error.
mkError :: (Show a, Typeable a, Typeable b) => a -> ConvResult b
mkError inpval = mkErrorGen "" inpval undefined
-- | Create conversion error with message.
mkError' :: (Show a, Typeable a, Typeable b)
=> String -> a -> ConvResult b
mkError' msg inpval = mkErrorGen msg inpval undefined
mkErrorGen :: (Show a, Typeable a, Typeable b)
=> String -> a -> b -> ConvResult b
mkErrorGen msg inp ret =
Left ConvError {jsonValue = show inp,
jsonType = show . typeOf $ inp,
destType = show . typeOf $ ret,
errorMessage = msg}
data ConvError = ConvError {
jsonValue :: String,
jsonType :: String,
destType :: String,
errorMessage :: String}
deriving (Eq, Read, Show)
instance Error ConvError where
strMsg s = ConvError "" "" "" s