{-# LANGUAGE CPP #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
#if __GLASGOW_HASKELL__ < 710
{-# LANGUAGE OverlappingInstances #-}
#endif
module Text.JSON.Canonical.Class (
ToJSON(..)
, FromJSON(..)
, ToObjectKey(..)
, FromObjectKey(..)
, ReportSchemaErrors(..)
, Expected
, Got
, expectedButGotValue
, fromJSObject
, fromJSField
, fromJSOptField
, mkObject
) where
import Text.JSON.Canonical.Types
import Control.Monad (foldM, liftM)
import Data.Maybe (catMaybes)
import Data.Map (Map)
import qualified Data.Map as Map
#if !(MIN_VERSION_base(4,8,0))
import Control.Applicative (Applicative, (<$>), (<*>))
#endif
class ToJSON m a where
toJSON :: a -> m JSValue
class FromJSON m a where
fromJSON :: JSValue -> m a
class ToObjectKey m a where
toObjectKey :: a -> m JSString
class FromObjectKey m a where
fromObjectKey :: JSString -> m (Maybe a)
class (Applicative m, Monad m) => ReportSchemaErrors m where
expected :: Expected -> Maybe Got -> m a
type Expected = String
type Got = String
expectedButGotValue :: ReportSchemaErrors m => Expected -> JSValue -> m a
expectedButGotValue :: Expected -> JSValue -> m a
expectedButGotValue Expected
descr JSValue
val = Expected -> Maybe Expected -> m a
forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> Maybe Expected -> m a
expected Expected
descr (Expected -> Maybe Expected
forall a. a -> Maybe a
Just (JSValue -> Expected
describeValue JSValue
val))
where
describeValue :: JSValue -> String
describeValue :: JSValue -> Expected
describeValue (JSValue
JSNull ) = Expected
"null"
describeValue (JSBool Bool
_) = Expected
"bool"
describeValue (JSNum Int54
_) = Expected
"num"
describeValue (JSString JSString
_) = Expected
"string"
describeValue (JSArray [JSValue]
_) = Expected
"array"
describeValue (JSObject [(JSString, JSValue)]
_) = Expected
"object"
unknownField :: ReportSchemaErrors m => JSString -> m a
unknownField :: JSString -> m a
unknownField JSString
field = Expected -> Maybe Expected -> m a
forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> Maybe Expected -> m a
expected (Expected
"field " Expected -> Expected -> Expected
forall a. [a] -> [a] -> [a]
++ JSString -> Expected
forall a. Show a => a -> Expected
show JSString
field) Maybe Expected
forall a. Maybe a
Nothing
instance Monad m => ToObjectKey m JSString where
toObjectKey :: JSString -> m JSString
toObjectKey = JSString -> m JSString
forall (m :: * -> *) a. Monad m => a -> m a
return
instance Monad m => FromObjectKey m JSString where
fromObjectKey :: JSString -> m (Maybe JSString)
fromObjectKey = Maybe JSString -> m (Maybe JSString)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe JSString -> m (Maybe JSString))
-> (JSString -> Maybe JSString) -> JSString -> m (Maybe JSString)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JSString -> Maybe JSString
forall a. a -> Maybe a
Just
instance Monad m => ToObjectKey m String where
toObjectKey :: Expected -> m JSString
toObjectKey = JSString -> m JSString
forall (m :: * -> *) a. Monad m => a -> m a
return (JSString -> m JSString)
-> (Expected -> JSString) -> Expected -> m JSString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expected -> JSString
toJSString
instance Monad m => FromObjectKey m String where
fromObjectKey :: JSString -> m (Maybe Expected)
fromObjectKey = Maybe Expected -> m (Maybe Expected)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Expected -> m (Maybe Expected))
-> (JSString -> Maybe Expected) -> JSString -> m (Maybe Expected)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expected -> Maybe Expected
forall a. a -> Maybe a
Just (Expected -> Maybe Expected)
-> (JSString -> Expected) -> JSString -> Maybe Expected
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JSString -> Expected
fromJSString
instance Monad m => ToJSON m JSValue where
toJSON :: JSValue -> m JSValue
toJSON = JSValue -> m JSValue
forall (m :: * -> *) a. Monad m => a -> m a
return
instance Monad m => FromJSON m JSValue where
fromJSON :: JSValue -> m JSValue
fromJSON = JSValue -> m JSValue
forall (m :: * -> *) a. Monad m => a -> m a
return
instance Monad m => ToJSON m JSString where
toJSON :: JSString -> m JSValue
toJSON = JSValue -> m JSValue
forall (m :: * -> *) a. Monad m => a -> m a
return (JSValue -> m JSValue)
-> (JSString -> JSValue) -> JSString -> m JSValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JSString -> JSValue
JSString
instance ReportSchemaErrors m => FromJSON m JSString where
fromJSON :: JSValue -> m JSString
fromJSON (JSString JSString
str) = JSString -> m JSString
forall (m :: * -> *) a. Monad m => a -> m a
return JSString
str
fromJSON JSValue
val = Expected -> JSValue -> m JSString
forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> JSValue -> m a
expectedButGotValue Expected
"string" JSValue
val
instance Monad m => ToJSON m String where
toJSON :: Expected -> m JSValue
toJSON = JSValue -> m JSValue
forall (m :: * -> *) a. Monad m => a -> m a
return (JSValue -> m JSValue)
-> (Expected -> JSValue) -> Expected -> m JSValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JSString -> JSValue
JSString (JSString -> JSValue)
-> (Expected -> JSString) -> Expected -> JSValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expected -> JSString
toJSString
instance ReportSchemaErrors m => FromJSON m String where
fromJSON :: JSValue -> m Expected
fromJSON (JSString JSString
str) = Expected -> m Expected
forall (m :: * -> *) a. Monad m => a -> m a
return (JSString -> Expected
fromJSString JSString
str)
fromJSON JSValue
val = Expected -> JSValue -> m Expected
forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> JSValue -> m a
expectedButGotValue Expected
"string" JSValue
val
instance Monad m => ToJSON m Int54 where
toJSON :: Int54 -> m JSValue
toJSON = JSValue -> m JSValue
forall (m :: * -> *) a. Monad m => a -> m a
return (JSValue -> m JSValue) -> (Int54 -> JSValue) -> Int54 -> m JSValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int54 -> JSValue
JSNum
instance ReportSchemaErrors m => FromJSON m Int54 where
fromJSON :: JSValue -> m Int54
fromJSON (JSNum Int54
i) = Int54 -> m Int54
forall (m :: * -> *) a. Monad m => a -> m a
return Int54
i
fromJSON JSValue
val = Expected -> JSValue -> m Int54
forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> JSValue -> m a
expectedButGotValue Expected
"int" JSValue
val
instance
#if __GLASGOW_HASKELL__ >= 710
{-# OVERLAPPABLE #-}
#endif
(Monad m, ToJSON m a) => ToJSON m [a] where
toJSON :: [a] -> m JSValue
toJSON = ([JSValue] -> JSValue) -> m [JSValue] -> m JSValue
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM [JSValue] -> JSValue
JSArray (m [JSValue] -> m JSValue)
-> ([a] -> m [JSValue]) -> [a] -> m JSValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> m JSValue) -> [a] -> m [JSValue]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM' a -> m JSValue
forall (m :: * -> *) a. ToJSON m a => a -> m JSValue
toJSON
instance
#if __GLASGOW_HASKELL__ >= 710
{-# OVERLAPPABLE #-}
#endif
(ReportSchemaErrors m, FromJSON m a) => FromJSON m [a] where
fromJSON :: JSValue -> m [a]
fromJSON (JSArray [JSValue]
as) = (JSValue -> m a) -> [JSValue] -> m [a]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM' JSValue -> m a
forall (m :: * -> *) a. FromJSON m a => JSValue -> m a
fromJSON [JSValue]
as
fromJSON JSValue
val = Expected -> JSValue -> m [a]
forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> JSValue -> m a
expectedButGotValue Expected
"array" JSValue
val
instance ( Monad m
, ToObjectKey m k
, ToJSON m a
) => ToJSON m (Map k a) where
toJSON :: Map k a -> m JSValue
toJSON = ([(JSString, JSValue)] -> JSValue)
-> m [(JSString, JSValue)] -> m JSValue
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM [(JSString, JSValue)] -> JSValue
JSObject (m [(JSString, JSValue)] -> m JSValue)
-> (Map k a -> m [(JSString, JSValue)]) -> Map k a -> m JSValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((k, a) -> m (JSString, JSValue))
-> [(k, a)] -> m [(JSString, JSValue)]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM' (k, a) -> m (JSString, JSValue)
aux ([(k, a)] -> m [(JSString, JSValue)])
-> (Map k a -> [(k, a)]) -> Map k a -> m [(JSString, JSValue)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map k a -> [(k, a)]
forall k a. Map k a -> [(k, a)]
Map.toList
where
aux :: (k, a) -> m (JSString, JSValue)
aux :: (k, a) -> m (JSString, JSValue)
aux (k
k, a
a) = (,) (JSString -> JSValue -> (JSString, JSValue))
-> m JSString -> m (JSValue -> (JSString, JSValue))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> k -> m JSString
forall (m :: * -> *) a. ToObjectKey m a => a -> m JSString
toObjectKey k
k m (JSValue -> (JSString, JSValue))
-> m JSValue -> m (JSString, JSValue)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> a -> m JSValue
forall (m :: * -> *) a. ToJSON m a => a -> m JSValue
toJSON a
a
instance ( ReportSchemaErrors m
, Ord k
, FromObjectKey m k
, FromJSON m a
) => FromJSON m (Map k a) where
fromJSON :: JSValue -> m (Map k a)
fromJSON JSValue
enc = do
[(JSString, JSValue)]
obj <- JSValue -> m [(JSString, JSValue)]
forall (m :: * -> *).
ReportSchemaErrors m =>
JSValue -> m [(JSString, JSValue)]
fromJSObject JSValue
enc
[(k, a)] -> Map k a
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ([(k, a)] -> Map k a)
-> ([Maybe (k, a)] -> [(k, a)]) -> [Maybe (k, a)] -> Map k a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe (k, a)] -> [(k, a)]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe (k, a)] -> Map k a) -> m [Maybe (k, a)] -> m (Map k a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((JSString, JSValue) -> m (Maybe (k, a)))
-> [(JSString, JSValue)] -> m [Maybe (k, a)]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM_reverse (JSString, JSValue) -> m (Maybe (k, a))
aux [(JSString, JSValue)]
obj
where
aux :: (JSString, JSValue) -> m (Maybe (k, a))
aux :: (JSString, JSValue) -> m (Maybe (k, a))
aux (JSString
k, JSValue
a) = Maybe k -> a -> Maybe (k, a)
knownKeys (Maybe k -> a -> Maybe (k, a))
-> m (Maybe k) -> m (a -> Maybe (k, a))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JSString -> m (Maybe k)
forall (m :: * -> *) a.
FromObjectKey m a =>
JSString -> m (Maybe a)
fromObjectKey JSString
k m (a -> Maybe (k, a)) -> m a -> m (Maybe (k, a))
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> JSValue -> m a
forall (m :: * -> *) a. FromJSON m a => JSValue -> m a
fromJSON JSValue
a
knownKeys :: Maybe k -> a -> Maybe (k, a)
knownKeys :: Maybe k -> a -> Maybe (k, a)
knownKeys Maybe k
Nothing a
_ = Maybe (k, a)
forall a. Maybe a
Nothing
knownKeys (Just k
k) a
a = (k, a) -> Maybe (k, a)
forall a. a -> Maybe a
Just (k
k, a
a)
fromJSObject :: ReportSchemaErrors m => JSValue -> m [(JSString, JSValue)]
fromJSObject :: JSValue -> m [(JSString, JSValue)]
fromJSObject (JSObject [(JSString, JSValue)]
obj) = [(JSString, JSValue)] -> m [(JSString, JSValue)]
forall (m :: * -> *) a. Monad m => a -> m a
return [(JSString, JSValue)]
obj
fromJSObject JSValue
val = Expected -> JSValue -> m [(JSString, JSValue)]
forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> JSValue -> m a
expectedButGotValue Expected
"object" JSValue
val
fromJSField :: (ReportSchemaErrors m, FromJSON m a)
=> JSValue -> JSString -> m a
fromJSField :: JSValue -> JSString -> m a
fromJSField JSValue
val JSString
nm = do
[(JSString, JSValue)]
obj <- JSValue -> m [(JSString, JSValue)]
forall (m :: * -> *).
ReportSchemaErrors m =>
JSValue -> m [(JSString, JSValue)]
fromJSObject JSValue
val
case JSString -> [(JSString, JSValue)] -> Maybe JSValue
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup JSString
nm [(JSString, JSValue)]
obj of
Just JSValue
fld -> JSValue -> m a
forall (m :: * -> *) a. FromJSON m a => JSValue -> m a
fromJSON JSValue
fld
Maybe JSValue
Nothing -> JSString -> m a
forall (m :: * -> *) a. ReportSchemaErrors m => JSString -> m a
unknownField JSString
nm
fromJSOptField :: (ReportSchemaErrors m, FromJSON m a)
=> JSValue -> JSString -> m (Maybe a)
fromJSOptField :: JSValue -> JSString -> m (Maybe a)
fromJSOptField JSValue
val JSString
nm = do
[(JSString, JSValue)]
obj <- JSValue -> m [(JSString, JSValue)]
forall (m :: * -> *).
ReportSchemaErrors m =>
JSValue -> m [(JSString, JSValue)]
fromJSObject JSValue
val
case JSString -> [(JSString, JSValue)] -> Maybe JSValue
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup JSString
nm [(JSString, JSValue)]
obj of
Just JSValue
fld -> a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> m a -> m (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JSValue -> m a
forall (m :: * -> *) a. FromJSON m a => JSValue -> m a
fromJSON JSValue
fld
Maybe JSValue
Nothing -> Maybe a -> m (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe a
forall a. Maybe a
Nothing
mkObject :: forall m. Monad m => [(JSString, m JSValue)] -> m JSValue
mkObject :: [(JSString, m JSValue)] -> m JSValue
mkObject = ([(JSString, JSValue)] -> JSValue)
-> m [(JSString, JSValue)] -> m JSValue
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM [(JSString, JSValue)] -> JSValue
JSObject (m [(JSString, JSValue)] -> m JSValue)
-> ([(JSString, m JSValue)] -> m [(JSString, JSValue)])
-> [(JSString, m JSValue)]
-> m JSValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(JSString, m JSValue)] -> m [(JSString, JSValue)]
sequenceFields
where
sequenceFields :: [(JSString, m JSValue)] -> m [(JSString, JSValue)]
sequenceFields :: [(JSString, m JSValue)] -> m [(JSString, JSValue)]
sequenceFields [] = [(JSString, JSValue)] -> m [(JSString, JSValue)]
forall (m :: * -> *) a. Monad m => a -> m a
return []
sequenceFields ((JSString
fld,m JSValue
val):[(JSString, m JSValue)]
flds) = do JSValue
val' <- m JSValue
val
[(JSString, JSValue)]
flds' <- [(JSString, m JSValue)] -> m [(JSString, JSValue)]
sequenceFields [(JSString, m JSValue)]
flds
[(JSString, JSValue)] -> m [(JSString, JSValue)]
forall (m :: * -> *) a. Monad m => a -> m a
return ((JSString
fld,JSValue
val')(JSString, JSValue)
-> [(JSString, JSValue)] -> [(JSString, JSValue)]
forall a. a -> [a] -> [a]
:[(JSString, JSValue)]
flds')
mapM' :: Monad m => (a -> m b) -> [a] -> m [b]
mapM' :: (a -> m b) -> [a] -> m [b]
mapM' a -> m b
f = ([b] -> [b]) -> m [b] -> m [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [b] -> [b]
forall a. [a] -> [a]
reverse (m [b] -> m [b]) -> ([a] -> m [b]) -> [a] -> m [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> m b) -> [a] -> m [b]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM_reverse a -> m b
f
mapM_reverse :: Monad m => (a -> m b) -> [a] -> m [b]
mapM_reverse :: (a -> m b) -> [a] -> m [b]
mapM_reverse a -> m b
f = ([b] -> a -> m [b]) -> [b] -> [a] -> m [b]
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM (\[b]
xs a
a -> (b -> [b]) -> m b -> m [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (b -> [b] -> [b]
forall a. a -> [a] -> [a]
:[b]
xs) (a -> m b
f a
a)) []