{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeSynonymInstances #-}
module E.Metadata
( Metadata(..)
, MetadataError(..)
, E.Metadata.singleton
, addCiphered
, getCiphered
) where
import Control.Lens
import Data.Aeson (FromJSON, ToJSON)
import qualified Data.Aeson as Aeson
import Data.Aeson.Encode.Pretty
import qualified Data.ByteString.Lazy as BSL
import Data.Either.MoreCombinators
import Data.Hashable
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as Map
import Data.Semigroup
import Data.Text.Encoding
import GHC.Generics
import qualified Data.Text.Lazy as TL
import Data.Text.Lazy.Builder
import E.Template
data MetadataError
= MetadataInconsistentValues ValName
deriving (Eq,Show)
newtype Metadata = Metadata { unMetadata :: HashMap ValName EncValue }
deriving (Show,Eq,Generic,FromJSON,ToJSON)
instance Semigroup Metadata where
Metadata x <> Metadata y = Metadata (x <> y)
instance Monoid Metadata where
mappend = (<>)
mempty = Metadata mempty
singleton :: ValName -> EncValue -> Metadata
singleton v c = Metadata (Map.singleton v c)
insert' :: (Eq k, Hashable k, Eq v) => k -> v -> HashMap k v -> Maybe (HashMap k v)
insert' k v m = either id Just (at k aux m)
where
aux Nothing = Right (Just v)
aux (Just v') | v' == v = Left (Just m)
| otherwise = Left Nothing
addCiphered :: ValName -> EncValue -> Metadata -> Either MetadataError Metadata
addCiphered name evc (Metadata m) = Metadata <$>
note (MetadataInconsistentValues name) (insert' name evc m)
getCiphered :: ValName -> Metadata -> Maybe EncValue
getCiphered v (Metadata m) = Map.lookup v m
instance Serialize Metadata where
encode = TL.toStrict . toLazyText . encodePrettyToTextBuilder' (defConfig { confCompare = keyOrder ["name", "alg", "value", "args"] })
decode = Aeson.decode . BSL.fromStrict . encodeUtf8