{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Data.Mergeable.IsMap
  ( IsMap (..),
    selectBy,
    selectOr,
    FromList (..),
  )
where

import Control.Monad.Except (MonadError (throwError))
#if MIN_VERSION_aeson(2,0,0)
import Data.Aeson.Key (Key)
import qualified Data.Aeson.KeyMap as A
#endif
import qualified Data.HashMap.Lazy as HM
import Data.Mergeable.Internal.Merge (mergeNoDuplicates)
import Data.Mergeable.Internal.NameCollision (NameCollision)
import Relude

class IsMap k m | m -> k where
  unsafeFromList :: [(k, a)] -> m a

  singleton :: k -> a -> m a

  lookup :: k -> m a -> Maybe a

  member :: k -> m a -> Bool
  member = forall k (c :: * -> *) d a.
IsMap k c =>
d -> (a -> d) -> k -> c a -> d
selectOr Bool
False (forall a b. a -> b -> a
const Bool
True)

  toAssoc :: m a -> [(k, a)]

instance (Eq k, Hashable k) => IsMap k (HashMap k) where
  unsafeFromList :: forall a. [(k, a)] -> HashMap k a
unsafeFromList = forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HM.fromList
  singleton :: forall a. k -> a -> HashMap k a
singleton = forall k v. Hashable k => k -> v -> HashMap k v
HM.singleton
  lookup :: forall a. k -> HashMap k a -> Maybe a
lookup = forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HM.lookup
  member :: forall a. k -> HashMap k a -> Bool
member = forall k a. (Eq k, Hashable k) => k -> HashMap k a -> Bool
HM.member
  toAssoc :: forall a. HashMap k a -> [(k, a)]
toAssoc = forall k v. HashMap k v -> [(k, v)]
HM.toList

#if MIN_VERSION_aeson(2,0,0)
instance IsMap Key A.KeyMap where
  unsafeFromList :: forall a. [(Key, a)] -> KeyMap a
unsafeFromList = forall a. [(Key, a)] -> KeyMap a
A.fromList
  singleton :: forall a. Key -> a -> KeyMap a
singleton = forall a. Key -> a -> KeyMap a
A.singleton
  lookup :: forall a. Key -> KeyMap a -> Maybe a
lookup = forall a. Key -> KeyMap a -> Maybe a
A.lookup
  member :: forall a. Key -> KeyMap a -> Bool
member = forall a. Key -> KeyMap a -> Bool
A.member
  toAssoc :: forall a. KeyMap a -> [(Key, a)]
toAssoc = forall a. KeyMap a -> [(Key, a)]
A.toList
#endif

selectBy :: (MonadError e m, IsMap k c, Monad m) => e -> k -> c a -> m a
selectBy :: forall e (m :: * -> *) k (c :: * -> *) a.
(MonadError e m, IsMap k c, Monad m) =>
e -> k -> c a -> m a
selectBy e
err = forall k (c :: * -> *) d a.
IsMap k c =>
d -> (a -> d) -> k -> c a -> d
selectOr (forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError e
err) forall (f :: * -> *) a. Applicative f => a -> f a
pure

selectOr :: IsMap k c => d -> (a -> d) -> k -> c a -> d
selectOr :: forall k (c :: * -> *) d a.
IsMap k c =>
d -> (a -> d) -> k -> c a -> d
selectOr d
fb a -> d
f k
key c a
lib = forall b a. b -> (a -> b) -> Maybe a -> b
maybe d
fb a -> d
f (forall k (m :: * -> *) a. IsMap k m => k -> m a -> Maybe a
lookup k
key c a
lib)

class FromList m map k a where
  fromList :: (Monad m) => [(k, a)] -> m (map k a)

instance (Hashable k, Eq k, MonadError e m, NameCollision e a) => FromList m HashMap k a where
  fromList :: Monad m => [(k, a)] -> m (HashMap k a)
fromList = forall k (m :: * -> *) e a b.
(Eq k, Hashable k, Monad m, MonadError e m, NameCollision e a) =>
([(k, a)] -> b) -> [(k, a)] -> m b
mergeNoDuplicates forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HM.fromList