Skip to content

Instantly share code, notes, and snippets.

@chessai
Created November 30, 2018 20:21
Show Gist options
  • Save chessai/ea5cc18f60dbf434d0637389c9f93569 to your computer and use it in GitHub Desktop.
Save chessai/ea5cc18f60dbf434d0637389c9f93569 to your computer and use it in GitHub Desktop.
aeson instances for dmap
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}
{-# OPTIONS_GHC -Wall -Werror -fno-warn-orphans #-}
module Data.Dependent.Map.JSON () where
import Data.Aeson (ToJSON(..),FromJSON(..))
import Data.Exists (Exists(..),ToJSONKeyForall(..),
ToJSONKeyFunctionForall(..),ToJSONForall(..),ToSing(..),
FromJSONForall(..),FromJSONKeyExists(..))
import Data.Dependent.Map (DMap)
import Data.HashMap.Strict (HashMap)
import Data.Text (Text)
import Data.Foldable (foldlM)
import qualified Data.Dependent.Map as DM
import qualified Data.HashMap.Strict as HM
import qualified Data.Aeson as AE
import qualified Data.Aeson.Types as AET
instance (ToJSONKeyForall k, ToJSONForall v) => ToJSON (DMap k v) where
toJSON dm = case toJSONKeyForall of
ToJSONKeyTextForall toText _ -> AE.Object (DM.foldlWithKey (f toText) HM.empty dm)
ToJSONKeyValueForall toValue _ -> toJSON (DM.foldrWithKey (g toValue) [] dm)
where
f :: forall a. (k a -> Text) -> HashMap Text AE.Value -> k a -> v a -> HashMap Text AE.Value
f toText hm k v = HM.insert (toText k) (toJSONForall v) hm
g :: forall a. (k a -> AE.Value) -> k a -> v a -> [(AE.Value,AE.Value)] -> [(AE.Value,AE.Value)]
g toValue k v xs = (toValue k, toJSONForall v) : xs
instance (DM.GCompare k, FromJSONKeyExists k, FromJSONForall v, ToSing k) => FromJSON (DMap k v) where
parseJSON obj = case fromJSONKeyExists of
AE.FromJSONKeyCoerce _ -> error "FromJSON instance for DMap: this cannot happen"
AE.FromJSONKeyText fromText -> AE.withObject "DMap"
(HM.foldrWithKey (f1 fromText) (pure DM.empty))
obj
AE.FromJSONKeyTextParser fromText -> AE.withObject "DMap"
(HM.foldrWithKey (f2 fromText) (pure DM.empty))
obj
AE.FromJSONKeyValue fromValue -> AE.withArray "DMap"
(foldlM (f3 fromValue) DM.empty)
obj
where
f1 :: (Text -> Exists k) -> Text -> AE.Value -> AET.Parser (DMap k v) -> AET.Parser (DMap k v)
f1 fromText keyText valRaw m = case fromText keyText of
Exists key -> do
let keySing = toSing key
val <- parseJSONForall keySing valRaw
dm <- m
pure (DM.insert key val dm)
f2 :: (Text -> AET.Parser (Exists k)) -> Text -> AE.Value -> AET.Parser (DMap k v) -> AET.Parser (DMap k v)
f2 fromText keyText valRaw m = do
Exists key <- fromText keyText
let keySing = toSing key
val <- parseJSONForall keySing valRaw
dm <- m
pure (DM.insert key val dm)
f3 :: (AE.Value -> AET.Parser (Exists k)) -> DMap k v -> AE.Value -> AET.Parser (DMap k v)
f3 fromValue dm pairRaw = do
(keyRaw :: AE.Value,valRaw :: AE.Value) <- parseJSON pairRaw
Exists key <- fromValue keyRaw
let keySing = toSing key
val <- parseJSONForall keySing valRaw
pure (DM.insert key val dm)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment