packages feed

prosidy-1.5.0.1: src/Prosidy/Types/Assoc.hs

{-|
Module      : Prosidy.Types.Assoc
Description : An associative mapping of keys to values.
Copyright   : ©2020 James Alexander Feldman-Crough
License     : MPL-2.0
Maintainer  : alex@fldcr.com
-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Prosidy.Types.Assoc (Assoc(..), asHashMap, fromHashMap, toHashMap) where

import           Data.HashMap.Strict            ( HashMap )
import           GHC.Generics                   ( Generic )
import           Data.Aeson                     ( ToJSON(..)
                                                , FromJSON(..)
                                                )
import           Control.DeepSeq                ( NFData )
import           Data.Binary                    ( Binary(..) )
import           Data.Hashable                  ( Hashable(..) )

import qualified Data.HashMap.Strict           as HM

-- | An associative mapping of keys to values.
--
-- Currently implemented as a 'HashMap', this newtype wrapper allows us to:
--
-- 1) Add non-orphan instances to the underlying structure.
-- 2) Change the underlying type if needed.
newtype Assoc k v = Assoc (HashMap k v)
  deriving stock (Generic)
  deriving newtype (Eq, Foldable, Functor, Show, ToJSON, FromJSON, NFData, Semigroup, Monoid, Hashable)

instance (Eq k, Hashable k, Binary k, Binary v) => Binary (Assoc k v) where
    get = Assoc . HM.fromList <$> get

    put (Assoc hm) = put $ HM.toList hm

-- | Given a function which operates on a 'HashMap', return a function which
-- performs an equivalent transfromation on an 'Assoc'.
asHashMap
    :: Functor f
    => (HashMap k v -> f (HashMap k' v'))
    -> Assoc k v
    -> f (Assoc k' v')
asHashMap f (Assoc a) = Assoc <$> f a

-- | Convert a 'HashMap' to an 'Assoc'.
fromHashMap :: HashMap k v -> Assoc k v
fromHashMap = Assoc

-- | Convert an 'Assoc' to a 'HashMap'.
toHashMap :: Assoc k v -> HashMap k v
toHashMap (Assoc hm) = hm