{-# LANGUAGE AllowAmbiguousTypes #-}

-- | Handy utilities for defining predicates.

module Rerefined.Predicate.Common
  (
  -- * Re-exports
    module Rerefined.Predicate
  , Typeably(..), Typeable
  , proxy#

  -- * Predicate validation
  , validateFail, validateBool

  -- * Predicate name
  , predicateName1, predicateName2
  ) where

import Rerefined.Predicate
import GHC.Exts ( Proxy#, proxy# )
import Data.Typeable.Typeably
import Data.Typeable ( Typeable )

-- | Shortcut for returning a predicate validation failure.
validateFail
    :: forall p
    .  Predicate p
    => Proxy# p -> String -> [RefineFailure String]
    -> Maybe (RefineFailure String)
validateFail :: forall {k} (p :: k).
Predicate p =>
Proxy# p
-> String -> [RefineFailure String] -> Maybe (RefineFailure String)
validateFail Proxy# p
p String
msg [RefineFailure String]
es = RefineFailure String -> Maybe (RefineFailure String)
forall a. a -> Maybe a
Just (RefineFailure String -> Maybe (RefineFailure String))
-> RefineFailure String -> Maybe (RefineFailure String)
forall a b. (a -> b) -> a -> b
$ String -> String -> [RefineFailure String] -> RefineFailure String
forall a. a -> a -> [RefineFailure a] -> RefineFailure a
RefineFailure (Proxy# p -> Int -> ShowS
forall {k} (p :: k). Predicate p => Proxy# p -> Int -> ShowS
predicateName Proxy# p
p Int
0 String
"") String
msg [RefineFailure String]
es

-- | Shortcut for simply validating a 'Bool'.
validateBool
    :: Predicate p => Proxy# p -> String -> Bool
    -> Maybe (RefineFailure String)
validateBool :: forall {k} (p :: k).
Predicate p =>
Proxy# p -> String -> Bool -> Maybe (RefineFailure String)
validateBool Proxy# p
p String
e = \case
  Bool
True  -> Maybe (RefineFailure String)
forall a. Maybe a
Nothing
  Bool
False -> Proxy# p
-> String -> [RefineFailure String] -> Maybe (RefineFailure String)
forall {k} (p :: k).
Predicate p =>
Proxy# p
-> String -> [RefineFailure String] -> Maybe (RefineFailure String)
validateFail Proxy# p
p String
e []

predicateName1 :: forall p. Predicate p => String -> Int -> ShowS
predicateName1 :: forall {k} (p :: k). Predicate p => String -> Int -> ShowS
predicateName1 String
pName Int
d = Bool -> ShowS -> ShowS
showParen (Int
d Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
10) (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
      String -> ShowS
showString String
pName ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ShowS
showChar Char
' '
    ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Proxy# p -> Int -> ShowS
forall {k} (p :: k). Predicate p => Proxy# p -> Int -> ShowS
predicateName (forall (a :: k). Proxy# a
forall {k} (a :: k). Proxy# a
proxy# @p) Int
11

predicateName2
    :: forall l r. (Predicate l, Predicate r) => String -> Int -> ShowS
predicateName2 :: forall {k} {k} (l :: k) (r :: k).
(Predicate l, Predicate r) =>
String -> Int -> ShowS
predicateName2 String
pName Int
d = Bool -> ShowS -> ShowS
showParen (Int
d Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
10) (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
      String -> ShowS
showString String
pName ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ShowS
showChar Char
' '
    ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Proxy# l -> Int -> ShowS
forall {k} (p :: k). Predicate p => Proxy# p -> Int -> ShowS
predicateName (forall (a :: k). Proxy# a
forall {k} (a :: k). Proxy# a
proxy# @l) Int
11 ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ShowS
showChar Char
' '
    ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Proxy# r -> Int -> ShowS
forall {k} (p :: k). Predicate p => Proxy# p -> Int -> ShowS
predicateName (forall (a :: k). Proxy# a
forall {k} (a :: k). Proxy# a
proxy# @r) Int
11