module Concurrent.Capability.Pinned
  ( Pinned(..)
  , runPinned
  , ReifiesCapability(..)
  ) where
import Concurrent.Thread
import Control.Applicative
import Control.Monad
import Control.Monad.Catch
import Control.Monad.Primitive
import Data.Tagged
import Unsafe.Coerce
newtype Pinned s a = Pinned { unpinned :: IO a }
  deriving (Functor,Applicative,Monad,Alternative,MonadPlus,MonadThrow,MonadCatch,MonadMask)
instance PrimMonad (Pinned s) where
  type PrimState (Pinned s) = RealWorld
  primitive m = Pinned (primitive m)
  
instance PrimBase (Pinned s) where
  internal (Pinned m) = internal m
  
class ReifiesCapability s where
  reflectCapability :: Tagged s Int
instance ReifiesCapability s => ReifiesCapability (Pinned s) where
  reflectCapability = retag (reflectCapability :: Tagged s Int)
reifyCapability :: forall r. (forall (s :: *). ReifiesCapability s => Pinned s r) -> Int -> IO r
reifyCapability k = unsafeCoerce (Magic k :: Magic r)
newtype Magic r = Magic (forall (s :: *). ReifiesCapability s => Pinned s r)
runPinned :: (forall (s :: *). ReifiesCapability s => Pinned s a) -> IO a
runPinned m = withCapability (currentCapability >>= reifyCapability m)