{-# language MagicHash #-}
{-# language UnboxedTuples #-}
{-# language LambdaCase #-}
-- |
-- Copyright :  (c) 2019-2021 Edward Kmett
-- License   :  BSD-2-Clause OR Apache-2.0
-- Maintainer:  Edward Kmett <ekmett@gmail.com>
-- Stability :  experimental
-- Portability: non-portable
--
module System.Mem.Weak.IORef
( mkWeakIORef'
, mkWeakIORefPtr
, mkWeakIORefPair
) where

import GHC.Base
import GHC.Weak
import GHC.IORef
import GHC.STRef

-- | Make an arbitrary 'Weak' reference from a 'Data.IORef.IORef'.
--
-- Provides a more general API than the crippled one offered by 'Data.IORef.mkWeakIORef'
-- to match the power of 'mkWeak'.
mkWeakIORef' :: IORef k -> v -> Maybe (IO ()) -> IO (Weak v)
mkWeakIORef' (IORef (STRef k#)) v = \case
  Nothing             -> IO $ \s -> case mkWeakNoFinalizer# k# v s of (# s1, w #) -> (#s1, Weak w #)
  Just (IO finalizer) -> IO $ \s -> case mkWeak# k# v finalizer s of (# s1, w #) -> (#s1, Weak w #)
{-# inlinable mkWeakIORef' #-}

-- | Functions like 'System.Mem.Weak.mkWeakPtr' but for 'Data.IORef.IORef's.
--
-- Make an arbitrary 'Weak' reference from an 'Data.IORef.IORef' and an optional finalizer.
--
-- A specialised version of 'mkWeakIORef'' where the key and value are the same.
mkWeakIORefPtr :: IORef k -> Maybe (IO ()) -> IO (Weak (IORef k))
mkWeakIORefPtr k = mkWeakIORef' k k
{-# inlinable mkWeakIORefPtr #-}

-- | 
--
-- A specialised version of 'mkWeakIORef'' where the value is actually a pair of the
-- key and value passed to 'mkWeakIORefPair':
--
-- @
-- 'mkWeakIORefPair' key val finalizer ≡ 'mkWeakIORef'' key (key,val) finalizer
-- @
--
-- The advantage of this is that the key can be retrieved by 'deRefWeak' in addition to the value.
mkWeakIORefPair :: IORef k -> v -> Maybe (IO ()) -> IO (Weak (IORef k, v))
mkWeakIORefPair k v = mkWeakIORef' k (k,v)
{-# inlinable mkWeakIORefPair #-}