module Disposable ( Disposable(EmptyDisposable)
, newDisposable
, dispose
, DisposableSet
, newDisposableSet
, addDisposable
, removeDisposable
, toDisposable
) where
import Control.Applicative
import Control.Monad
import Data.Maybe
import Data.Foldable as F
import Data.Sequence as Seq
import Data.IORef
import Data.Unique
data Disposable where
EmptyDisposable :: Disposable
Disposable :: Unique -> IORef (Maybe (IO ())) -> Disposable
instance Eq Disposable where
EmptyDisposable == EmptyDisposable = True
(Disposable u _) == (Disposable u' _) = u == u'
_ == _ = False
dispose :: Disposable -> IO ()
dispose EmptyDisposable = return ()
dispose (Disposable _ mref) = do
m <- atomicModifyIORef mref $ \m -> (Nothing, m)
fromMaybe (return ()) m
newDisposable :: IO () -> IO Disposable
newDisposable action = do
u <- newUnique
mref <- newIORef $ Just action
return $ Disposable u mref
type MaybeSet = Maybe (Seq Disposable)
newtype DisposableSet = DisposableSet (IORef MaybeSet)
newDisposableSet :: IO DisposableSet
newDisposableSet = do
mref <- newIORef $ Just Seq.empty
return $ DisposableSet mref
toDisposable :: DisposableSet -> IO Disposable
toDisposable (DisposableSet mref) =
let disposeSet = F.mapM_ dispose
action = do
m <- atomicModifyIORef mref $ \m -> (Nothing, m)
maybe (return ()) disposeSet m
in newDisposable action
addDisposable :: DisposableSet -> Disposable -> IO ()
addDisposable _ EmptyDisposable = return ()
addDisposable (DisposableSet mref) d =
let addDisposable' Nothing = (Nothing, True)
addDisposable' (Just s) = (Just $ s |> d, False)
in do
b <- atomicModifyIORef mref addDisposable'
when b $ dispose d
removeDisposable :: DisposableSet -> Disposable -> IO ()
removeDisposable _ EmptyDisposable = return ()
removeDisposable (DisposableSet mref) d =
let removeDisposable' = liftM $ Seq.filter (/= d)
in atomicModifyIORef mref $ \m -> (removeDisposable' m, ())