{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
module Internal.Rc
( Rc
, new
, get
, incr
, decr
, release
) where
import Control.Concurrent.STM
newtype Rc a
= Rc (TVar (Maybe (RcState a)))
deriving(Eq)
data RcState a = RcState
{ refCount :: !Int
, value :: a
, finalizer :: STM ()
}
new :: a -> STM () -> STM (Rc a)
new value finalizer = fmap Rc $ newTVar $ Just RcState
{ refCount = 1
, value
, finalizer
}
incr :: Rc a -> STM ()
incr (Rc tv) = modifyTVar' tv $
fmap $ \s@RcState{refCount} -> s { refCount = refCount + 1 }
decr :: Rc a -> STM ()
decr (Rc tv) = readTVar tv >>= \case
Nothing ->
pure ()
Just RcState{refCount=1, finalizer} -> do
writeTVar tv Nothing
finalizer
Just s@RcState{refCount} ->
writeTVar tv $ Just s { refCount = refCount - 1 }
release :: Rc a -> STM ()
release (Rc tv) = readTVar tv >>= \case
Nothing ->
pure ()
Just RcState{finalizer} -> do
finalizer
writeTVar tv Nothing
get :: Rc a -> STM (Maybe a)
get (Rc tv) = fmap value <$> readTVar tv