recover-rtti-0.4.0.0: src/Debug/RecoverRTTI/Constraint.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}
-- | Establish that a constraint holds for all classified types
module Debug.RecoverRTTI.Constraint (
PrimSatisfies
, primSatisfies
, ClassifiedSatisfies
, classifiedSatisfies
) where
import Data.Aeson (Value)
import Data.HashMap.Lazy (HashMap)
import Data.HashSet (HashSet)
import Data.Int
import Data.IntMap (IntMap)
import Data.IntSet (IntSet)
import Data.Kind
import Data.Map (Map)
import Data.Ratio
import Data.Sequence (Seq)
import Data.Set (Set)
import Data.SOP
import Data.SOP.Dict
import Data.Tree (Tree)
import Data.Void
import Data.Word
import qualified Data.ByteString as BS.Strict
import qualified Data.ByteString.Lazy as BS.Lazy
import qualified Data.ByteString.Short as BS.Short
import qualified Data.HashMap.Internal.Array as HashMap (Array)
import qualified Data.Primitive.Array as Prim (Array)
import qualified Data.Text as Text.Strict
import qualified Data.Text.Lazy as Text.Lazy
import qualified Data.Vector as Vector.Boxed
import Debug.RecoverRTTI.Classifier
import Debug.RecoverRTTI.Nat
import Debug.RecoverRTTI.Tuple
import Debug.RecoverRTTI.Wrappers
{-------------------------------------------------------------------------------
Primitives
-------------------------------------------------------------------------------}
type PrimSatisfies (c :: Type -> Constraint) = (
-- Primitive types
c Bool
, c Char
, c Double
, c Float
, c Int
, c Int16
, c Int8
, c Int32
, c Int64
, c Integer
, c Ordering
, c ()
, c Word
, c Word8
, c Word16
, c Word32
, c Word64
-- String types
, c String
, c BS.Strict.ByteString
, c BS.Lazy.ByteString
, c BS.Short.ShortByteString
, c Text.Strict.Text
, c Text.Lazy.Text
-- Aeson
, c Value
-- Reference cells
, c SomeSTRef
, c SomeTVar
, c SomeMVar
-- Functions
, c SomeFun
-- Containers with no type arguments
, c IntSet
, c SomePrimArrayM
, c SomeStorableVector
, c SomeStorableVectorM
, c SomePrimitiveVector
, c SomePrimitiveVectorM
)
primSatisfies :: forall c.
PrimSatisfies c
=> (forall a. PrimClassifier a -> Dict c a)
primSatisfies = go
where
go :: PrimClassifier a -> Dict c a
-- Primitive types
go C_Bool = Dict
go C_Char = Dict
go C_Double = Dict
go C_Float = Dict
go C_Int = Dict
go C_Int16 = Dict
go C_Int8 = Dict
go C_Int32 = Dict
go C_Int64 = Dict
go C_Integer = Dict
go C_Ordering = Dict
go C_Unit = Dict
go C_Word = Dict
go C_Word8 = Dict
go C_Word16 = Dict
go C_Word32 = Dict
go C_Word64 = Dict
-- String types
go C_String = Dict
go C_BS_Strict = Dict
go C_BS_Lazy = Dict
go C_BS_Short = Dict
go C_Text_Strict = Dict
go C_Text_Lazy = Dict
-- Aeson
go C_Value = Dict
-- Reference cells
go C_STRef = Dict
go C_TVar = Dict
go C_MVar = Dict
-- Functions
go C_Fun = Dict
-- Containers with no type arguments
go C_IntSet = Dict
go C_Prim_ArrayM = Dict
go C_Vector_Storable = Dict
go C_Vector_StorableM = Dict
go C_Vector_Primitive = Dict
go C_Vector_PrimitiveM = Dict
{-------------------------------------------------------------------------------
Compound
We can't use a type alias for the constraint here as ghc doesn't like
quantified constraints in constraint type aliases.
-------------------------------------------------------------------------------}
class (
PrimSatisfies c
-- Compound
, forall a. (c a) => c (Maybe a)
, forall a b. (c a, c b) => c (Either a b)
, forall a. (c a) => c [a]
, forall a. (c a) => c (Ratio a)
, forall a. (c a) => c (Set a)
, forall a b. (c a, c b) => c (Map a b)
, forall a. (c a) => c (IntMap a)
, forall a. (c a) => c (Seq a)
, forall a. (c a) => c (Tree a)
, forall a. (c a) => c (HashSet a)
, forall a b. (c a, c b) => c (HashMap a b)
, forall a. (c a) => c (HashMap.Array a)
, forall a. (c a) => c (Prim.Array a)
, forall a. (c a) => c (Vector.Boxed.Vector a)
, forall xs. (All c xs, IsValidSize (Length xs)) => c (WrappedTuple xs)
) => ClassifiedSatisfies (c :: Type -> Constraint)
instance (
PrimSatisfies c
-- Compound
, forall a. (c a) => c (Maybe a)
, forall a b. (c a, c b) => c (Either a b)
, forall a. (c a) => c [a]
, forall a. (c a) => c (Ratio a)
, forall a. (c a) => c (Set a)
, forall a b. (c a, c b) => c (Map a b)
, forall a. (c a) => c (IntMap a)
, forall a. (c a) => c (Seq a)
, forall a. (c a) => c (Tree a)
, forall a. (c a) => c (HashSet a)
, forall a b. (c a, c b) => c (HashMap a b)
, forall a. (c a) => c (HashMap.Array a)
, forall a. (c a) => c (Prim.Array a)
, forall a. (c a) => c (Vector.Boxed.Vector a)
, forall xs. (All c xs, IsValidSize (Length xs)) => c (WrappedTuple xs)
) => ClassifiedSatisfies (c :: Type -> Constraint)
classifiedSatisfies :: forall c o.
(ClassifiedSatisfies c, c Void)
=> (forall a. o a -> Dict c a)
-> (forall a. Classifier_ o a -> Dict c a)
classifiedSatisfies otherSatisfies = go
where
go :: Classifier_ o a -> Dict c a
go (C_Prim c) = primSatisfies c
go (C_Other c) = otherSatisfies c
-- Compound
go (C_Maybe c) = goElems c $ Dict
go (C_Either c) = goElems c $ Dict
go (C_List c) = goElems c $ Dict
go (C_Ratio c) = goElems c $ Dict
go (C_Set c) = goElems c $ Dict
go (C_Map c) = goElems c $ Dict
go (C_IntMap c) = goElems c $ Dict
go (C_Sequence c) = goElems c $ Dict
go (C_Tree c) = goElems c $ Dict
go (C_HashSet c) = goElems c $ Dict
go (C_HashMap c) = goElems c $ Dict
go (C_HM_Array c) = goElems c $ Dict
go (C_Prim_Array c) = goElems c $ Dict
go (C_Vector_Boxed c) = goElems c $ Dict
go (C_Tuple c) = goElems c $ Dict
goElems :: SListI as => Elems o as -> (All c as => r) -> r
goElems (Elems cs) k = case all_NP (hmap goElem cs) of Dict -> k
goElem :: Elem o a -> Dict c a
goElem (Elem c) = go c
goElem NoElem = Dict