-- | A map to track and manage the debuggee runtime threads
module GHC.Debugger.Runtime.Thread.Map
  ( ThreadMap
  , emptyThreadMap

  -- * Operations
  , insertThreadMap
  , lookupThreadMap

  , threadMapToList

  -- can we detect when a thread has died? what happens if we have a reference
  -- to a ThreadId which has been GC'd?
  ) where

import Control.Concurrent
import Data.Coerce

import GHCi.RemoteTypes
import qualified Data.IntMap as IM

-- | A thread map maintains a mapping between the int thread identifier, which
-- uniquely identifies a thread spawned by the debuggee, and the (possibly
-- remote) reference to the thread (i.e. the corresponding ThreadId)
type ThreadMap = IM.IntMap (ForeignRef ThreadId)

-- | Insert a remote 'ThreadId' at this unique Int thread identifier
insertThreadMap :: Int -> ForeignRef ThreadId -> ThreadMap -> ThreadMap
insertThreadMap :: Key -> ForeignRef ThreadId -> ThreadMap -> ThreadMap
insertThreadMap = Key -> ForeignRef ThreadId -> ThreadMap -> ThreadMap
forall a. Key -> a -> IntMap a -> IntMap a
IM.insert

-- | Lookup a remote 'ThreadId' by its unique Int identifier
lookupThreadMap :: Int -> ThreadMap -> Maybe (ForeignRef ThreadId)
lookupThreadMap :: Key -> ThreadMap -> Maybe (ForeignRef ThreadId)
lookupThreadMap = Key -> ThreadMap -> Maybe (ForeignRef ThreadId)
forall a. Key -> IntMap a -> Maybe a
IM.lookup

-- | > It's empty, what did you expect?
emptyThreadMap :: ThreadMap
emptyThreadMap :: ThreadMap
emptyThreadMap = ThreadMap
forall a. IntMap a
IM.empty

-- | Get all the remote thread references from the ThreadMap
threadMapToList :: ThreadMap -> [(Int, ForeignRef ThreadId)]
threadMapToList :: ThreadMap -> [(Key, ForeignRef ThreadId)]
threadMapToList = [(Key, ForeignRef ThreadId)] -> [(Key, ForeignRef ThreadId)]
forall a b. Coercible a b => a -> b
coerce ([(Key, ForeignRef ThreadId)] -> [(Key, ForeignRef ThreadId)])
-> (ThreadMap -> [(Key, ForeignRef ThreadId)])
-> ThreadMap
-> [(Key, ForeignRef ThreadId)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ThreadMap -> [(Key, ForeignRef ThreadId)]
forall a. IntMap a -> [(Key, a)]
IM.toList