packages feed

recover-rtti-0.1.0.0: tests/Test/RecoverRTTI/UserDefined.hs

{-# LANGUAGE BangPatterns      #-}
{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE MagicHash         #-}
{-# LANGUAGE TypeFamilies      #-}
{-# LANGUAGE TypeOperators     #-}
{-# LANGUAGE UnboxedTuples     #-}

-- | Just some examples of user-defined types
module Test.RecoverRTTI.UserDefined (
    NonRecursive(..)
  , Recursive(..)
  , recursiveFromList
  , ContainsUnlifted -- opaque
  , exampleContainsUnlifted
  ) where

import GHC.Generics
import GHC.IO
import GHC.Prim

{-------------------------------------------------------------------------------
  User-defined datatypes
-------------------------------------------------------------------------------}

-- | Example of a non-recursive user-defined type
data NonRecursive a = NR1 Int | NR2 a Bool
  deriving (Show, Eq, Generic, Functor, Foldable, Traversable)

-- | Example of a recursive user-defined type
data Recursive a = RNil | RCons a (Recursive a)
  deriving (Show, Eq, Generic, Functor, Foldable, Traversable)

recursiveFromList :: [a] -> Recursive a
recursiveFromList = foldr RCons RNil

{-------------------------------------------------------------------------------
  Example of a type with an unlifted value

  Most instances here don't really make much sense; this is just here to
  verify we don't crash when coming across unlifted values
-------------------------------------------------------------------------------}

-- | Example of a user-defined type containing something unlifted
data ContainsUnlifted a = NothingHere | ContainsUnlifted (MutableArray# RealWorld Int) a
  deriving (Functor, Foldable, Traversable)

-- We can't derive a Generic instance, we must produce just enough info so that
-- we can do the right type casts
instance Generic (ContainsUnlifted a) where
  type Rep (ContainsUnlifted a) = Rep_ContainsUnlifted

  from = error "'from' not defined for ContainsUnlifted"
  to   = error "'to' not defined for ContainsUnlifted"

-- We don't bother specifiying the arguments to the constructors
type Rep_ContainsUnlifted =
    M1 D ('MetaData "ContainsUnlifted" "Test.RecoverRTTI.UserDefined" "main" 'False)
     (     M1 C ('MetaCons "NothingHere" 'PrefixI 'False) U1
       :+:
           M1 C ('MetaCons "ContainsUnlifted" 'PrefixI 'False) U1
     )

instance Show a => Show (ContainsUnlifted a) where
  showsPrec _ NothingHere =
        showString "NothingHere"
  showsPrec p (ContainsUnlifted _ x) = showParen (p >= 11) $
        showString "ContainsUnlifted "
      . showsPrec 11 x

instance Eq (ContainsUnlifted a) where
  _ == _ = True

exampleContainsUnlifted :: ContainsUnlifted ()
{-# NOINLINE exampleContainsUnlifted #-}
exampleContainsUnlifted = unsafePerformIO $ IO $ \world ->
    let !(# world', arr #) = newArray# 5# 0 world
    in (# world', ContainsUnlifted arr () #)