-- A first cut at implementing the (key,value) form of Weak pointers.
--
-- Notes (please refer to the draft specification for background):
--
--  - mkWeakPair is listed in the signature specification, but its
--    semantics are not described, and hence we have not provided
--    an implementation here.
--
--  - Programmers using weak pointers should call runFinalizer at
--    regular intervals to ensure that finalizers are scheduled for
--    execution.  This implementation provides functions runFinalizer,
--    finalizerWaiting, and runAllFinalizers to provide programmers with
--    control over the execution of finalizers.  None of these functions
--    are part of the current specification.
--
-- Tested with Hugs 98.

module Weak(Weak,
	    mkWeak, mkWeakPtr, mkWeakPair,
            deRefWeak, finalize, addFinalizer, replaceFinalizer,
	    runFinalizer, finalizerWaiting, runAllFinalizers ) where

data Weak a

primitive mkWeak    :: k -> v -> Maybe (IO ()) -> IO (Weak v)
primitive deRefWeak :: Weak v -> IO (Maybe v)
primitive replaceFinalizer :: Weak v -> Maybe (IO ()) -> IO (Maybe (IO ()))
primitive finalize  :: Weak v -> IO ()
primitive weakPtrEq :: Weak a -> Weak a -> Bool

instance Eq (Weak a) where
  (==) = weakPtrEq

mkWeakPtr           :: k -> Maybe (IO ()) -> IO (Weak k)
mkWeakPtr v f        = mkWeak v v f

mkWeakPair          :: k -> v -> Maybe (IO ()) -> IO (Weak (k,v))
mkWeakPair k v f     = mkWeak k (k,v) f

addFinalizer	    :: k -> IO () -> IO ()
addFinalizer v f     = do mkWeakPtr v (Just f)
			  return ()

primitive runFinalizer     :: IO ()
primitive finalizerWaiting :: IO Bool

runAllFinalizers    :: IO ()
runAllFinalizers     = do waiting <- finalizerWaiting
			  if waiting then do runFinalizer
					     runAllFinalizers
				     else return ()

{- for testing purposes
primitive gc "primGC" :: IO ()

-- not a CAF!
test z = do
  { let k = [z]		-- use a list so we're sure it's heap allocated
  ; print k		-- this makes sure x is in whnf
  ; w <- mkWeak k "value" (Just (putStrLn ("Finalizer for "++show k)))
			-- note that the finalizer uses the key, but
			-- this shouldn't keep the weak ptr alive!
  ; showWeakPtr w
  ; gc
  ; print k		-- this makes sure k is still alive after the GC
  ; showWeakPtr w	-- so it's probably still alive here
  ; gc
  ; showWeakPtr w	-- but ought to be dead by here
  }

showWeakPtr :: Show a => Weak a -> IO ()
showWeakPtr w = do
  { x <- deRefWeak w
  ; print x
  }

-}

-- End of module Weak
