packages feed

recover-rtti-0.6.0: tests/Test/RecoverRTTI/ConcreteClassifier/Constraint.hs

module Test.RecoverRTTI.ConcreteClassifier.Constraint (
    UserSatisfies
  , userSatisfies
  , concreteSatisfies
  , canShowConcrete
  , canCompareConcrete
  ) where

import Data.HashMap.Internal.Array qualified as HashMap (Array)
import Data.HashMap.Lazy (HashMap)
import Data.HashSet (HashSet)
import Data.IntMap (IntMap)
import Data.Kind
import Data.Map (Map)
import Data.Primitive.Array qualified as Prim (Array)
import Data.Ratio
import Data.Sequence (Seq)
import Data.Set (Set)
import Data.SOP
import Data.SOP.Dict
import Data.Tree (Tree)
import Data.Vector qualified as Vector.Boxed
import Data.Void

import Debug.RecoverRTTI (PrimSatisfies, primSatisfies)
import Debug.RecoverRTTI (IsValidSize, Length, WrappedTuple)

import Test.RecoverRTTI.ConcreteClassifier
import Test.RecoverRTTI.Orphans ()
import Test.RecoverRTTI.UserDefined

{-------------------------------------------------------------------------------
  User-defined types
-------------------------------------------------------------------------------}

class (
    c SimpleType
  , forall a. c a => c (NonRecursive a)
  , forall a. c a => c (Recursive    a)
  , c ContainsUnlifted
  ) => UserSatisfies c

instance (
    c SimpleType
  , forall a. c a => c (NonRecursive a)
  , forall a. c a => c (Recursive    a)
  , c ContainsUnlifted
  ) => UserSatisfies c

userSatisfies :: forall c a. ConcreteSatisfies c => ConcreteUser a -> Dict c a
userSatisfies = go
  where
    go :: forall x. ConcreteUser x -> Dict c x
    go  CC_Simple    = Dict
    go (CC_NonRec c) = case auxConcrete c of Dict -> Dict
    go (CC_Rec    c) = case auxConcrete c of Dict -> Dict
    go  CC_Unlifted  = Dict

    auxConcrete :: forall x. Concrete x -> Dict c x
    auxConcrete = concreteSatisfies

{-------------------------------------------------------------------------------
  Compound
-------------------------------------------------------------------------------}

class (
    PrimSatisfies c
  , UserSatisfies c
  , c Void
    -- 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)
  ) => ConcreteSatisfies (c :: Type -> Constraint)

instance (
    PrimSatisfies c
  , UserSatisfies c
  , c Void
    -- 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)
  ) => ConcreteSatisfies (c :: Type -> Constraint)

concreteSatisfies :: forall c a. ConcreteSatisfies c => Concrete a -> Dict c a
concreteSatisfies = go
  where
    go :: forall x. Concrete x -> Dict c x
    go (CC_Prim  c) = primSatisfies  c
    go (CC_Other c) = userSatisfies c
    go  CC_Void     = Dict

   -- Compound types with unclassified elements
    go (CC_HashSet      c1   ) = case go c1 of Dict -> Dict
    go (CC_IntMap       c1   ) = case go c1 of Dict -> Dict
    go (CC_Maybe        c1   ) = case go c1 of Dict -> Dict
    go (CC_Ratio        c1   ) = case go c1 of Dict -> Dict
    go (CC_Set          c1   ) = case go c1 of Dict -> Dict
    go (CC_Tree         c1   ) = case go c1 of Dict -> Dict

    go (CC_HM_Array     c1   ) = case go c1 of Dict -> Dict
    go (CC_List         c1   ) = case go c1 of Dict -> Dict
    go (CC_Prim_Array   c1   ) = case go c1 of Dict -> Dict
    go (CC_Sequence     c1   ) = case go c1 of Dict -> Dict
    go (CC_Vector_Boxed c1   ) = case go c1 of Dict -> Dict

    go (CC_Either       c1 c2) = case (go c1, go c2) of (Dict, Dict) -> Dict
    go (CC_HashMap      c1 c2) = case (go c1, go c2) of (Dict, Dict) -> Dict
    go (CC_Map          c1 c2) = case (go c1, go c2) of (Dict, Dict) -> Dict

    -- Compound types with classified elements
    go (CC_Tuple cs) = goNP cs Dict

    goNP :: SListI as => Concretes as -> (All c as => r) -> r
    goNP (Concretes cs) k = case all_NP (hmap go cs) of Dict -> k

canShowConcrete :: Concrete a -> Dict Show a
canShowConcrete = concreteSatisfies

canCompareConcrete :: Concrete a -> Dict Eq a
canCompareConcrete = concreteSatisfies