packages feed

servant-gdp-0.0.1.2: src/Servant/GDP/ProveInIsolation.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Servant.GDP.ProveInIsolation (ProvableInIsolation, proveInIsolation) where

import Data.Text (Text)
import GDP (Proof, introAnd, introOrL, introOrR, (...), type (&&), type (:::), type (||), type (~~))
import Servant
  ( FromHttpApiData,
    parseUrlPiece,
  )

-- | Check if property P holds for value a or not.
-- Is used to parse a value from the request with a required proof
class ProvableInIsolation a p where
  proveInIsolation :: a -> Either Text (Proof p)

instance (ProvableInIsolation a p1, ProvableInIsolation a p2) => ProvableInIsolation a (p1 && p2) where
  proveInIsolation x = do
    p1 <- proveInIsolation x
    p2 <- proveInIsolation x
    return $ introAnd p1 p2

instance (ProvableInIsolation a p1, ProvableInIsolation a p2) => ProvableInIsolation a (p1 || p2) where
  proveInIsolation x = do
    case (proveInIsolation x, proveInIsolation x) of
      (Right p1, _) -> return $ introOrL p1
      (_, Right p2) -> return $ introOrR p2
      (Left e1, Left e2) -> Left $ e1 <> e2

instance
  ( FromHttpApiData (a ~~ n),
    FromHttpApiData a,
    ProvableInIsolation (a ~~ n) p
  ) =>
  FromHttpApiData (a ~~ n ::: p)
  where
  parseUrlPiece t =
    do
      (j :: a ~~ n) <- parseUrlPiece t
      (j ...) <$> proveInIsolation j