-- This is a backend for the fact representation that uses a Git
-- repository as the store.

module EVM.Facts.Git
  ( saveFacts
  , loadFacts
  , RepoAt (..)
  ) where

import EVM.Facts (Fact (..), File (..), Path (..), Data (..), fileToFact, factToFile)

import Control.Lens
import Data.Set   (Set)
import Data.Maybe (catMaybes)

import qualified Data.Set         as Set
import qualified Restless.Git     as Git

newtype RepoAt = RepoAt String
  deriving (RepoAt -> RepoAt -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RepoAt -> RepoAt -> Bool
$c/= :: RepoAt -> RepoAt -> Bool
== :: RepoAt -> RepoAt -> Bool
$c== :: RepoAt -> RepoAt -> Bool
Eq, Eq RepoAt
RepoAt -> RepoAt -> Bool
RepoAt -> RepoAt -> Ordering
RepoAt -> RepoAt -> RepoAt
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: RepoAt -> RepoAt -> RepoAt
$cmin :: RepoAt -> RepoAt -> RepoAt
max :: RepoAt -> RepoAt -> RepoAt
$cmax :: RepoAt -> RepoAt -> RepoAt
>= :: RepoAt -> RepoAt -> Bool
$c>= :: RepoAt -> RepoAt -> Bool
> :: RepoAt -> RepoAt -> Bool
$c> :: RepoAt -> RepoAt -> Bool
<= :: RepoAt -> RepoAt -> Bool
$c<= :: RepoAt -> RepoAt -> Bool
< :: RepoAt -> RepoAt -> Bool
$c< :: RepoAt -> RepoAt -> Bool
compare :: RepoAt -> RepoAt -> Ordering
$ccompare :: RepoAt -> RepoAt -> Ordering
Ord, Int -> RepoAt -> String -> String
[RepoAt] -> String -> String
RepoAt -> String
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [RepoAt] -> String -> String
$cshowList :: [RepoAt] -> String -> String
show :: RepoAt -> String
$cshow :: RepoAt -> String
showsPrec :: Int -> RepoAt -> String -> String
$cshowsPrec :: Int -> RepoAt -> String -> String
Show)

-- For modularity reasons, we have our own file data type that is
-- isomorphic with the one in the `restless-git` library.  We declare
-- the isomorphism so we can go between them easily.
fileRepr :: Iso' File Git.File
fileRepr :: Iso' File File
fileRepr = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso File -> File
f File -> File
g
  where
    f :: File -> Git.File
    f :: File -> File
f (File     (Path [ASCII]
ps ASCII
p)     (Data ASCII
x)) =
      Path -> ASCII -> File
Git.File ([ASCII] -> ASCII -> Path
Git.Path [ASCII]
ps ASCII
p) ASCII
x

    g :: Git.File -> File
    g :: File -> File
g (Git.File (Git.Path [ASCII]
ps ASCII
p) ASCII
x) =
      Path -> Data -> File
File     ([ASCII] -> ASCII -> Path
Path [ASCII]
ps ASCII
p)     (ASCII -> Data
Data ASCII
x)

saveFacts :: RepoAt -> Set Fact -> IO ()
saveFacts :: RepoAt -> Set Fact -> IO ()
saveFacts (RepoAt String
repo) Set Fact
facts =
  forall (m :: * -> *).
(Monad m, MonadIO m) =>
String -> Text -> Set File -> m ()
Git.save String
repo Text
"hevm execution"
    (forall b a. Ord b => (a -> b) -> Set a -> Set b
Set.map (forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Iso' File File
fileRepr forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fact -> File
factToFile) Set Fact
facts)

prune :: Ord a => Set (Maybe a) -> Set a
prune :: forall a. Ord a => Set (Maybe a) -> Set a
prune = forall a. Ord a => [a] -> Set a
Set.fromList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [Maybe a] -> [a]
catMaybes forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Set a -> [a]
Set.toList

loadFacts :: RepoAt -> IO (Set Fact)
loadFacts :: RepoAt -> IO (Set Fact)
loadFacts (RepoAt String
src) =
  forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
    (forall a. Ord a => Set (Maybe a) -> Set a
prune forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b a. Ord b => (a -> b) -> Set a -> Set b
Set.map (File -> Maybe Fact
fileToFact forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (forall s t a b. AnIso s t a b -> Iso b a t s
from Iso' File File
fileRepr)))
    (forall (m :: * -> *).
(Monad m, MonadIO m) =>
String -> m (Set File)
Git.load String
src)