{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS -Wall #-}
module Types
( Op(..)
, MapDB(..)
, PureMapDB
, IOMapDB
)
where
import Control.Monad
import Control.Monad.Identity
import Control.Monad.IO.Class
import Control.Monad.State.Strict
import Data.Aeson
import Data.ByteString.Base16 as Base16
import Data.ByteString.Char8 as Strict
import Data.HashMap.Strict as HashMap
import Data.Map as Map
import Data.Text as Text
import Data.Text.Encoding
import DFINITY.RadixTree
data Op
= Insert ByteString ByteString
| Delete ByteString
| Lookup ByteString (Maybe ByteString)
| Merkleize (Maybe ByteString)
instance FromJSON Op where
parseJSON = \ case
Object obj -> maybe mzero pure $ parse obj
_ -> mzero
instance Show Op where
show = \ case
Insert key value -> "Insert" ++ pretty key ++ pretty value
Delete key -> "Delete" ++ pretty key
Lookup key value -> "Lookup" ++ pretty key ++ maybe " null" pretty value
Merkleize value -> "Merkleize" ++ maybe " null" pretty value
where pretty = mappend " 0x" . Strict.unpack . Base16.encode
parse :: Object -> Maybe Op
parse obj = do
op <- HashMap.lookup "op" obj
case op of
"set" -> do
key <- view obj "key"
val <- view obj "value"
pure $ Insert key val
"delete" -> do
key <- view obj "key"
pure $ Delete key
"get" -> do
key <- view obj "key"
let val = view obj "value"
pure $ Lookup key val
"stateRoot" -> do
let val = view obj "value"
pure $ Merkleize val
_ -> Nothing
view :: Object -> Text -> Maybe ByteString
view obj key = do
val <- HashMap.lookup key obj
case val of
String text -> Just $ fst $ Base16.decode $ encodeUtf8 $ Text.drop 2 text
_ -> Nothing
newtype MapDB m a
= MapDB { unMapDB :: StateT (Map ByteString ByteString) m a }
deriving (Functor, Applicative, Monad, MonadIO, MonadTrans)
instance Monad m => RadixDatabase (MapDB m) () where
load _ key = MapDB $ Map.lookup key <$> get
store _ key val = MapDB $ modify $ Map.insert key val
type PureMapDB = MapDB Identity
type IOMapDB = MapDB IO