-- |
-- Copyright: (c) 2021 Xy Ren
-- License: BSD3
-- Maintainer: xy.r@outlook.com
-- Stability: unstable
-- Portability: non-portable (GHC only)
--
-- This module contains common definitions for the @cleff@ internals.
--
-- __This is an /internal/ module and its API may change even between minor versions.__ Therefore you should be
-- extra careful if you're to depend on this module.
module Cleff.Internal
  ( -- * Basic types
    Effect
  , type (~>)
  , type (++)
  , HandlerPtr (HandlerPtr, unHandlerPtr)
    -- * The @Any@ type
  , Any
  , pattern Any
  , fromAny
    -- * Miscellaneous
  , noinline
  ) where

import           Data.Kind     (Type)
import           GHC.Exts      (Any)
import           Unsafe.Coerce (unsafeCoerce)

-- | The type of effects. An effect @e m a@ takes an effect monad type @m :: 'Type' -> 'Type'@ and a result type
-- @a :: 'Type'@.
type Effect = (Type -> Type) -> Type -> Type

-- | A natural transformation from @f@ to @g@. With this, instead of writing
--
-- @
-- runSomeEffect :: 'Cleff.Eff' (SomeEffect : es) a -> 'Cleff.Eff' es a
-- @
--
-- you can write:
--
-- @
-- runSomeEffect :: 'Cleff.Eff' (SomeEffect : es) ~> 'Cleff.Eff' es
-- @
type f ~> g =  a. f a -> g a

-- | Type level list concatenation.
type family xs ++ ys where
  '[] ++ ys = ys
  (x : xs) ++ ys = x : (xs ++ ys)
infixr 5 ++

-- | A pointer to an effect handler.
type role HandlerPtr nominal
newtype HandlerPtr (e :: Effect) = HandlerPtr { HandlerPtr e -> Int
unHandlerPtr :: Int }

-- | A pattern synonym for coercing values to and from 'Any'. This is not any less unsafe but prevents possivle
-- misuses.
pattern Any :: forall a. a -> Any
pattern $bAny :: a -> Any
$mAny :: forall r a. Any -> (a -> r) -> (Void# -> r) -> r
Any {Any -> a
fromAny} <- (unsafeCoerce -> fromAny)
  where Any = a -> Any
forall a b. a -> b
unsafeCoerce
{-# COMPLETE Any #-}

-- | Magic function that tells the compiler /not/ to inline the argument.
noinline :: a -> a
noinline :: a -> a
noinline a
x = a
x
{-# NOINLINE noinline #-}