{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE UndecidableInstances #-} ----------------------------------------------------------------------------- -- | -- Module : Data.Aeson.Extra.Map -- Copyright : (C) 2015-2016 Oleg Grenrus -- License : BSD3 -- Maintainer : Oleg Grenrus -- -- More or less useful newtypes for writing 'FromJSON' & 'ToJSON' instances module Data.Aeson.Extra.Map {-# DEPRECATED "Use aeson-1 TOJSONKey etc functionality" #-} ( M(..), FromJSONKey(..), parseIntegralJSONKey, FromJSONMap(..), ToJSONKey(..), ToJSONMap(..), ) where import Prelude () import Prelude.Compat import Data.Aeson.Compat (FromJSON (..), ToJSON (..), Value (..), withObject) import Data.Aeson.Types (Parser) import Data.Hashable (Hashable) import Data.Semigroup.Compat ((<>)) import Data.Text (Text) import Data.Typeable (Typeable) import qualified Data.HashMap.Strict as H import qualified Data.Map as Map import qualified Data.Text as T import qualified Data.Text.Lazy as TL import qualified Data.Text.Read as T -- | A wrapper type to parse arbitrary maps -- -- > λ > decode "{\"1\": 1, \"2\": 2}" :: Maybe (M (H.HashMap Int Int)) -- > Just (M {getMap = fromList [(1,1),(2,2)]}) newtype M a = M { getMap :: a } deriving (Eq, Ord, Show, Read, Functor, Foldable, Traversable, Typeable) {-# DEPRECATED M "Use aeson-1 TOJSONKey etc functionality" #-} class FromJSONKey a where parseJSONKey :: Text -> Parser a instance FromJSONKey Text where parseJSONKey = pure instance FromJSONKey TL.Text where parseJSONKey = pure . TL.fromStrict instance FromJSONKey String where parseJSONKey = pure . T.unpack instance FromJSONKey Int where parseJSONKey = parseIntegralJSONKey instance FromJSONKey Integer where parseJSONKey = parseIntegralJSONKey parseIntegralJSONKey :: Integral a => Text -> Parser a parseIntegralJSONKey t = case (T.signed T.decimal) t of Right (v, left) | T.null left -> pure v | otherwise -> fail $ "Garbage left: " <> T.unpack left Left err -> fail err class FromJSONMap m k v | m -> k v where parseJSONMap :: H.HashMap Text Value -> Parser m instance (Eq k, Hashable k, FromJSONKey k, FromJSON v) => FromJSONMap (H.HashMap k v) k v where parseJSONMap = fmap H.fromList . traverse f . H.toList where f (k, v) = (,) <$> parseJSONKey k <*> parseJSON v instance (Ord k, FromJSONKey k, FromJSON v) => FromJSONMap (Map.Map k v) k v where parseJSONMap = fmap Map.fromList . traverse f . H.toList where f (k, v) = (,) <$> parseJSONKey k <*> parseJSON v instance (FromJSONMap m k v) => FromJSON (M m) where parseJSON v = M <$> withObject "Map" parseJSONMap v class ToJSONKey a where toJSONKey :: a -> Text instance ToJSONKey Text where toJSONKey = id instance ToJSONKey TL.Text where toJSONKey = TL.toStrict instance ToJSONKey String where toJSONKey = T.pack instance ToJSONKey Int where toJSONKey = T.pack . show instance ToJSONKey Integer where toJSONKey = T.pack . show class ToJSONMap m k v | m -> k v where toJSONMap :: m -> H.HashMap Text Value instance (ToJSONKey k, ToJSON v) => ToJSONMap (H.HashMap k v) k v where toJSONMap = H.fromList . fmap f . H.toList where f (k, v) = (toJSONKey k, toJSON v) instance (ToJSONKey k, ToJSON v) => ToJSONMap (Map.Map k v) k v where toJSONMap = H.fromList . fmap f . Map.toList where f (k, v) = (toJSONKey k, toJSON v) instance (ToJSONMap m k v) => ToJSON (M m) where toJSON (M m) = Object (toJSONMap m)