{-# LANGUAGE UndecidableInstances #-}
module Data.Aeson.Deriving.Internal.RecordSum where
import Data.Aeson
import Data.Aeson.Types (Parser)
import Data.Bifunctor (first)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Kind (Type)
import Data.Proxy
import GHC.Generics
newtype ParserMap a = ParserMap (HashMap String (Value -> Parser a))
deriving stock Functor
deriving newtype (Semigroup, Monoid)
unsafeMapKeys :: (String -> String) -> ParserMap a -> ParserMap a
unsafeMapKeys f (ParserMap hm)
= ParserMap
. HashMap.fromList
. fmap (first f)
$ HashMap.toList hm
class GTagParserMap (repA :: Type -> Type) where
gParserMap :: Proxy repA -> ParserMap (repA x)
instance (GConstructorNames (Rep a), FromJSON a) => GTagParserMap (Rec0 a) where
gParserMap _ = ParserMap . HashMap.fromList $ do
constructorName <- gConstructorNames $ Proxy @(Rep a)
[(constructorName, fmap K1 . parseJSON)]
instance GTagParserMap repA => GTagParserMap (S1 meta repA) where
gParserMap _ = M1 <$> gParserMap (Proxy @repA)
instance GTagParserMap repA => GTagParserMap (C1 meta repA) where
gParserMap _ = M1 <$> gParserMap (Proxy @repA)
instance (GTagParserMap repA, GTagParserMap repB) => GTagParserMap (repA :+: repB) where
gParserMap _ =
(L1 <$> gParserMap (Proxy @repA))
<> (R1 <$> gParserMap (Proxy @repB))
instance GTagParserMap repA => GTagParserMap (D1 meta repA) where
gParserMap _ = M1 <$> gParserMap (Proxy @repA)
class GConstructorNames (repA :: Type -> Type) where
gConstructorNames :: Proxy repA -> [String]
instance Constructor constructorMeta => GConstructorNames (C1 constructorMeta r) where
gConstructorNames _ = [conName @constructorMeta undefined]
instance (GConstructorNames x, GConstructorNames y) => GConstructorNames (x :+: y) where
gConstructorNames _ =
gConstructorNames (Proxy @x)
<> gConstructorNames (Proxy @y)
instance GConstructorNames r => GConstructorNames (D1 datatypeMeta r) where
gConstructorNames _ = gConstructorNames $ Proxy @r