getRootSubscribed :: GCompare k => k a -> Root k -> EventM (RootSubscribed a)
getRootSubscribed k r = do
  mSubscribed <- liftIO $ readIORef $ rootSubscribed r
  case DMap.lookup (WrapArg k) mSubscribed of
    Just subscribed -> return subscribed
    Nothing -> liftIO $ do
      subscribersRef <- newIORef []
      subscribed <- newRootSubscribed (liftM (DMap.lookup k) $ readIORef $ rootOccurrence r) subscribersRef
      -- Strangely, init needs the same stuff as a RootSubscribed has, but it must not be the same as the one that everyone's subscribing to, or it'll leak memory
      uninit <- rootInit r k $ RootTrigger (subscribersRef, rootOccurrence r, k)
      addFinalizer subscribed $ do
        when noinlineFalse $ putStr "" -- For some reason, without this line, the finalizer will run earlier than it should
--        putStrLn "Uninit root"
        uninit
      liftIO $ modifyIORef' (rootSubscribed r) $ DMap.insert (WrapArg k) subscribed
      return subscribed

-- When getPushSubscribed returns, the PushSubscribed returned will have a fully filled-in
getRootSubscribed :: GCompare k => k a -> Root k -> EventM (RootSubscribed a)
getRootSubscribed k r = do
  mSubscribed <- liftIO $ readIORef $ rootSubscribed r
  case DMap.lookup (WrapArg k) mSubscribed of
    Just subscribed -> return subscribed
    Nothing -> liftIO $ do
      subscribersRef <- newIORef []
      subscribed <- newRootSubscribed (liftM (DMap.lookup k) $ readIORef $ rootOccurrence r) subscribersRef
      -- Strangely, init needs the same stuff as a RootSubscribed has, but it must not be the same as the one that everyone's subscribing to, or it'll leak memory
      uninit <- rootInit r k $ RootTrigger (subscribersRef, rootOccurrence r, k)
      addFinalizer subscribed $ do
        when noinlineFalse $ putStr "" -- For some reason, without this line, the finalizer will run earlier than it should
--        putStrLn "Uninit root"
        uninit
      liftIO $ modifyIORef' (rootSubscribed r) $ DMap.insert (WrapArg k) subscribed
      return subscribed

-- When getPushSubscribed returns, the PushSubscribed returned will have a fully filled-in
getRootSubscribed k r = do
  mSubscribed <- liftIO $ readIORef $ rootSubscribed r
  case DMap.lookup (WrapArg k) mSubscribed of
    Just subscribed -> return subscribed
    Nothing -> liftIO $ do
      subscribersRef <- newIORef []
      subscribed <- newRootSubscribed (liftM (DMap.lookup k) $ readIORef $ rootOccurrence r) subscribersRef
      -- Strangely, init needs the same stuff as a RootSubscribed has, but it must not be the same as the one that everyone's subscribing to, or it'll leak memory
      uninit <- rootInit r k $ RootTrigger (subscribersRef, rootOccurrence r, k)
      addFinalizer subscribed $ do
        when noinlineFalse $ putStr "" -- For some reason, without this line, the finalizer will run earlier than it should
--        putStrLn "Uninit root"
        uninit
      liftIO $ modifyIORef' (rootSubscribed r) $ DMap.insert (WrapArg k) subscribed
      return subscribed

-- When getPushSubscribed returns, the PushSubscribed returned will have a fully filled-in