{-# 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 k -> v -> Maybe (IO ()) -> IO (Weak v)
mkWeakIORef' (IORef (STRef MutVar# RealWorld k
k#)) v
v = \case
  Maybe (IO ())
Nothing             -> (State# RealWorld -> (# State# RealWorld, Weak v #)) -> IO (Weak v)
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld -> (# State# RealWorld, Weak v #))
 -> IO (Weak v))
-> (State# RealWorld -> (# State# RealWorld, Weak v #))
-> IO (Weak v)
forall a b. (a -> b) -> a -> b
$ \State# RealWorld
s -> case MutVar# RealWorld k
-> v -> State# RealWorld -> (# State# RealWorld, Weak# v #)
forall a b.
a -> b -> State# RealWorld -> (# State# RealWorld, Weak# b #)
mkWeakNoFinalizer# MutVar# RealWorld k
k# v
v State# RealWorld
s of (# State# RealWorld
s1, Weak# v
w #) -> (#State# RealWorld
s1, Weak# v -> Weak v
forall v. Weak# v -> Weak v
Weak Weak# v
w #)
  Just (IO State# RealWorld -> (# State# RealWorld, () #)
finalizer) -> (State# RealWorld -> (# State# RealWorld, Weak v #)) -> IO (Weak v)
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld -> (# State# RealWorld, Weak v #))
 -> IO (Weak v))
-> (State# RealWorld -> (# State# RealWorld, Weak v #))
-> IO (Weak v)
forall a b. (a -> b) -> a -> b
$ \State# RealWorld
s -> case MutVar# RealWorld k
-> v
-> (State# RealWorld -> (# State# RealWorld, () #))
-> State# RealWorld
-> (# State# RealWorld, Weak# v #)
forall a b c.
a
-> b
-> (State# RealWorld -> (# State# RealWorld, c #))
-> State# RealWorld
-> (# State# RealWorld, Weak# b #)
mkWeak# MutVar# RealWorld k
k# v
v State# RealWorld -> (# State# RealWorld, () #)
finalizer State# RealWorld
s of (# State# RealWorld
s1, Weak# v
w #) -> (#State# RealWorld
s1, Weak# v -> Weak v
forall v. Weak# v -> Weak v
Weak Weak# v
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 :: IORef k -> Maybe (IO ()) -> IO (Weak (IORef k))
mkWeakIORefPtr IORef k
k = IORef k -> IORef k -> Maybe (IO ()) -> IO (Weak (IORef k))
forall k v. IORef k -> v -> Maybe (IO ()) -> IO (Weak v)
mkWeakIORef' IORef k
k IORef 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 :: IORef k -> v -> Maybe (IO ()) -> IO (Weak (IORef k, v))
mkWeakIORefPair IORef k
k v
v = IORef k -> (IORef k, v) -> Maybe (IO ()) -> IO (Weak (IORef k, v))
forall k v. IORef k -> v -> Maybe (IO ()) -> IO (Weak v)
mkWeakIORef' IORef k
k (IORef k
k,v
v)
{-# inlinable mkWeakIORefPair #-}