    {-# LANGUAGE CPP, StandaloneDeriving, GeneralizedNewtypeDeriving #-}

    -- |
    -- Types for referring to remote objects in Remote GHCi.  For more
    -- details, see Note [External GHCi pointers] in compiler/GHC/Runtime/Interpreter.hs
    --
    -- For details on Remote GHCi, see Note [Remote GHCi] in
    -- compiler/GHC/Runtime/Interpreter.hs.
    --
    module GHCi.RemoteTypes
      ( -- * Remote pointer
        RemotePtr(..)
      , toRemotePtr
      , fromRemotePtr
      , castRemotePtr
      -- * RemoteRef: reference to some heap object (potentially remote)
      , RemoteRef (..)
      , mkRemoteRef
      , localRef
      , freeRemoteRef
      , castRemoteRef
      -- * ForeignRef: RemoteRef with a finalizer
      , ForeignRef
      , mkForeignRef
      , withForeignRef
      , finalizeForeignRef
      , castForeignRef
      , unsafeForeignRefToRemoteRef
      -- * HValue
      , HValue(..)
      , HValueRef
      , ForeignHValue
    ) where

    import Prelude -- See note [Why do we import Prelude here?]
    import Control.DeepSeq
    import Data.Word
    import Foreign hiding (newForeignPtr)
    import Foreign.Concurrent
    import Data.Binary
    import GHC.Exts
    import GHC.ForeignPtr

    -- -----------------------------------------------------------------------------
    -- RemotePtr

    -- Static pointers only; don't use this for heap-resident pointers.
    -- Instead use HValueRef. We will fix the remote pointer to be 64 bits. This
    -- should cover 64 and 32bit systems, and permits the exchange of remote ptrs
    -- between machines of different word size. For example, when connecting to
    -- an iserv instance on a different architecture with different word size via
    -- -fexternal-interpreter.
    newtype RemotePtr a = RemotePtr Word64

    toRemotePtr :: Ptr a -> RemotePtr a
    toRemotePtr :: forall a. Ptr a -> RemotePtr a
    toRemotePtr Ptr a
    p = Word64 -> RemotePtr a
    forall {k} (a :: k). Word64 -> RemotePtr a
    RemotePtr (WordPtr -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Ptr a -> WordPtr
    forall a. Ptr a -> WordPtr
    ptrToWordPtr Ptr a
    p))

    fromRemotePtr :: RemotePtr a -> Ptr a
    fromRemotePtr :: forall a. RemotePtr a -> Ptr a
    fromRemotePtr (RemotePtr Word64
    p) = WordPtr -> Ptr a
    forall a. WordPtr -> Ptr a
    wordPtrToPtr (Word64 -> WordPtr
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word64
    p)

    castRemotePtr :: RemotePtr a -> RemotePtr b
    castRemotePtr :: forall {k} {k} (a :: k) (b :: k). RemotePtr a -> RemotePtr b
    castRemotePtr (RemotePtr Word64
    a) = Word64 -> RemotePtr b
    forall {k} (a :: k). Word64 -> RemotePtr a
    RemotePtr Word64
    a

    deriving instance Show (RemotePtr a)
    deriving instance Binary (RemotePtr a)
    deriving instance NFData (RemotePtr a)

    -- -----------------------------------------------------------------------------
    -- HValue: alias for Any

    newtype HValue = HValue Any

    instance Show HValue where
      show :: HValue -> String
    show HValue
    _ = String
    "<HValue>"

    -- For convenience
    type HValueRef     = RemoteRef HValue
    type ForeignHValue = ForeignRef HValue

    -- -----------------------------------------------------------------------------
    -- RemoteRef: pointer to a Heap object

    -- | A reference to a heap object. Potentially in a remote heap!
    -- These are allocated and freed explicitly.
    newtype RemoteRef a = RemoteRef (RemotePtr ())
      deriving (Int -> RemoteRef a -> ShowS
    [RemoteRef a] -> ShowS
    RemoteRef a -> String
    (Int -> RemoteRef a -> ShowS)
    -> (RemoteRef a -> String)
    -> ([RemoteRef a] -> ShowS)
    -> Show (RemoteRef a)
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    forall k (a :: k). Int -> RemoteRef a -> ShowS
    forall k (a :: k). [RemoteRef a] -> ShowS
    forall k (a :: k). RemoteRef a -> String
    $cshowsPrec :: forall k (a :: k). Int -> RemoteRef a -> ShowS
    showsPrec :: Int -> RemoteRef a -> ShowS
    $cshow :: forall k (a :: k). RemoteRef a -> String
    show :: RemoteRef a -> String
    $cshowList :: forall k (a :: k). [RemoteRef a] -> ShowS
    showList :: [RemoteRef a] -> ShowS
    Show, Get (RemoteRef a)
    [RemoteRef a] -> Put
    RemoteRef a -> Put
    (RemoteRef a -> Put)
    -> Get (RemoteRef a)
    -> ([RemoteRef a] -> Put)
    -> Binary (RemoteRef a)
    forall t. (t -> Put) -> Get t -> ([t] -> Put) -> Binary t
    forall k (a :: k). Get (RemoteRef a)
    forall k (a :: k). [RemoteRef a] -> Put
    forall k (a :: k). RemoteRef a -> Put
    $cput :: forall k (a :: k). RemoteRef a -> Put
    put :: RemoteRef a -> Put
    $cget :: forall k (a :: k). Get (RemoteRef a)
    get :: Get (RemoteRef a)
    $cputList :: forall k (a :: k). [RemoteRef a] -> Put
    putList :: [RemoteRef a] -> Put
    Binary)

    -- We can discard type information if we want
    castRemoteRef :: RemoteRef a -> RemoteRef b
    castRemoteRef :: forall {k} {k} (a :: k) (b :: k). RemoteRef a -> RemoteRef b
    castRemoteRef = RemoteRef a -> RemoteRef b
    forall a b. Coercible a b => a -> b
    coerce

    -- | Make a reference to a local value that we can send remotely.
    -- This reference will keep the value that it refers to alive until
    -- 'freeRemoteRef' is called.
    mkRemoteRef :: a -> IO (RemoteRef a)
    mkRemoteRef :: forall a. a -> IO (RemoteRef a)
    mkRemoteRef a
    a = do
      sp <- a -> IO (StablePtr a)
    forall a. a -> IO (StablePtr a)
    newStablePtr a
    a
      return $! RemoteRef (toRemotePtr (castStablePtrToPtr sp))

    -- | Convert a RemoteRef to its carried type. Should only be used if the
    -- RemoteRef originated in this process.
    localRef :: RemoteRef a -> IO a
    localRef :: forall a. RemoteRef a -> IO a
    localRef (RemoteRef RemotePtr ()
    w) =
      StablePtr a -> IO a
    forall a. StablePtr a -> IO a
    deRefStablePtr (Ptr () -> StablePtr a
    forall a. Ptr () -> StablePtr a
    castPtrToStablePtr (RemotePtr () -> Ptr ()
    forall a. RemotePtr a -> Ptr a
    fromRemotePtr RemotePtr ()
    w))

    -- | Release a RemoteRef that originated in this process
    freeRemoteRef :: RemoteRef a -> IO ()
    freeRemoteRef :: forall {k} (a :: k). RemoteRef a -> IO ()
    freeRemoteRef (RemoteRef RemotePtr ()
    w) =
      StablePtr (ZonkAny 0) -> IO ()
    forall a. StablePtr a -> IO ()
    freeStablePtr (Ptr () -> StablePtr (ZonkAny 0)
    forall a. Ptr () -> StablePtr a
    castPtrToStablePtr (RemotePtr () -> Ptr ()
    forall a. RemotePtr a -> Ptr a
    fromRemotePtr RemotePtr ()
    w))

    -- | An RemoteRef with a finalizer
    newtype ForeignRef a = ForeignRef (ForeignPtr ())

    instance NFData (ForeignRef a) where
      rnf :: ForeignRef a -> ()
    rnf ForeignRef a
    x = ForeignRef a
    x ForeignRef a -> () -> ()
    forall a b. a -> b -> b
    `seq` ()

    -- | Create a 'ForeignRef' from a 'RemoteRef'.  The finalizer
    -- should arrange to call 'freeRemoteRef' on the 'RemoteRef'.  (since
    -- this function needs to be called in the process that created the
    -- 'RemoteRef', it cannot be called directly from the finalizer).
    mkForeignRef :: RemoteRef a -> IO () -> IO (ForeignRef a)
    mkForeignRef :: forall {k} (a :: k). RemoteRef a -> IO () -> IO (ForeignRef a)
    mkForeignRef (RemoteRef RemotePtr ()
    hvref) IO ()
    finalizer =
      ForeignPtr () -> ForeignRef a
    forall {k} (a :: k). ForeignPtr () -> ForeignRef a
    ForeignRef (ForeignPtr () -> ForeignRef a)
    -> IO (ForeignPtr ()) -> IO (ForeignRef a)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Ptr () -> IO () -> IO (ForeignPtr ())
    forall a. Ptr a -> IO () -> IO (ForeignPtr a)
    newForeignPtr (RemotePtr () -> Ptr ()
    forall a. RemotePtr a -> Ptr a
    fromRemotePtr RemotePtr ()
    hvref) IO ()
    finalizer

    -- | Use a 'ForeignRef'
    withForeignRef :: ForeignRef a -> (RemoteRef a -> IO b) -> IO b
    withForeignRef :: forall {k} (a :: k) b.
    ForeignRef a -> (RemoteRef a -> IO b) -> IO b
    withForeignRef (ForeignRef ForeignPtr ()
    fp) RemoteRef a -> IO b
    f =
       ForeignPtr () -> (Ptr () -> IO b) -> IO b
    forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
    withForeignPtr ForeignPtr ()
    fp (RemoteRef a -> IO b
    f (RemoteRef a -> IO b) -> (Ptr () -> RemoteRef a) -> Ptr () -> IO b
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . RemotePtr () -> RemoteRef a
    forall {k} (a :: k). RemotePtr () -> RemoteRef a
    RemoteRef (RemotePtr () -> RemoteRef a)
    -> (Ptr () -> RemotePtr ()) -> Ptr () -> RemoteRef a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Ptr () -> RemotePtr ()
    forall a. Ptr a -> RemotePtr a
    toRemotePtr)

    unsafeForeignRefToRemoteRef :: ForeignRef a -> RemoteRef a
    unsafeForeignRefToRemoteRef :: forall {k} (a :: k). ForeignRef a -> RemoteRef a
    unsafeForeignRefToRemoteRef (ForeignRef ForeignPtr ()
    fp) =
      RemotePtr () -> RemoteRef a
    forall {k} (a :: k). RemotePtr () -> RemoteRef a
    RemoteRef (Ptr () -> RemotePtr ()
    forall a. Ptr a -> RemotePtr a
    toRemotePtr (ForeignPtr () -> Ptr ()
    forall a. ForeignPtr a -> Ptr a
    unsafeForeignPtrToPtr ForeignPtr ()
    fp))

    finalizeForeignRef :: ForeignRef a -> IO ()
    finalizeForeignRef :: forall {k} (a :: k). ForeignRef a -> IO ()
    finalizeForeignRef (ForeignRef ForeignPtr ()
    fp) = ForeignPtr () -> IO ()
    forall a. ForeignPtr a -> IO ()
    finalizeForeignPtr ForeignPtr ()
    fp

    castForeignRef :: ForeignRef a -> ForeignRef b
    castForeignRef :: forall {k} {k} (a :: k) (b :: k). ForeignRef a -> ForeignRef b
    castForeignRef = ForeignRef a -> ForeignRef b
    forall a b. Coercible a b => a -> b
    coerce