packages feed

prosidy-1.6.0.2: 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 Safe #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE OverloadedStrings #-}
module Prosidy.Types.Assoc
    ( Assoc(..)
    , asHashMap
    , fromHashMap
    , toHashMap
    , toEntries
    )
where

import           Prosidy.Internal.Classes

import           Data.HashMap.Strict            ( HashMap )

import qualified Data.HashMap.Strict           as HM
import qualified Data.Text.Prettyprint.Doc     as PP

-- | 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 (Generic)
  deriving (Eq, Show, ToJSON, FromJSON, NFData, Semigroup, Monoid, Hashable) via HashMap k v
  deriving (Foldable, Functor) via HashMap k

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

instance (Pretty k, Pretty v) => Pretty (Assoc k v) where
    pretty (Assoc hm) =
        PP.list
            . map (\(k, v) -> pretty k PP.<+> PP.equals PP.<+> pretty v)
            $ 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

-- | Convert an 'Assoc' into a list of key/value pairs.
toEntries :: Assoc k v -> [(k, v)]
toEntries (Assoc hm) = HM.toList hm