{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
#if GHCJS_FAST_WEAK
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE JavaScriptFFI #-}
#endif
module Reflex.FastWeak
( FastWeakTicket
, FastWeak
, mkFastWeakTicket
, getFastWeakTicketValue
, getFastWeakTicketWeak
, getFastWeakValue
, getFastWeakTicket
, emptyFastWeak
#ifdef GHCJS_FAST_WEAK
, unsafeFromRawJSVal
, unsafeToRawJSVal
, js_isNull
#endif
) where
import GHC.Exts (Any)
import Unsafe.Coerce
#ifdef GHCJS_FAST_WEAK
import GHCJS.Types
#else
import Control.Exception (evaluate)
import System.IO.Unsafe
import System.Mem.Weak
#endif
#ifdef GHCJS_FAST_WEAK
newtype FastWeakTicket a = FastWeakTicket JSVal
newtype FastWeak a = FastWeak JSVal
data Val a = Val { unVal :: a }
unsafeFromRawJSVal :: JSVal -> a
unsafeFromRawJSVal v = unVal (unsafeCoerce v)
unsafeToRawJSVal :: a -> JSVal
unsafeToRawJSVal v = unsafeCoerce (Val v)
#else
data FastWeakTicket a = FastWeakTicket
{ _fastWeakTicket_val :: !a
, _fastWeakTicket_weak :: {-# UNPACK #-} !(Weak a)
}
type FastWeak a = Weak a
#endif
getFastWeakTicketValue :: FastWeakTicket a -> IO a
#ifdef GHCJS_FAST_WEAK
getFastWeakTicketValue t = do
v <- js_ticketVal t
return $ unsafeFromRawJSVal v
foreign import javascript unsafe "$r = $1.val;" js_ticketVal :: FastWeakTicket a -> IO JSVal
#else
getFastWeakTicketValue = return . _fastWeakTicket_val
#endif
getFastWeakValue :: FastWeak a -> IO (Maybe a)
#ifdef GHCJS_FAST_WEAK
getFastWeakValue w = do
r <- js_weakVal w
case js_isNull r of
True -> return Nothing
False -> return $ Just $ unsafeFromRawJSVal r
foreign import javascript unsafe "$1 === null" js_isNull :: JSVal -> Bool
foreign import javascript unsafe "$r = ($1.ticket === null) ? null : $1.ticket.val;" js_weakVal :: FastWeak a -> IO JSVal
#else
getFastWeakValue = deRefWeak
#endif
getFastWeakTicket :: forall a. FastWeak a -> IO (Maybe (FastWeakTicket a))
#ifdef GHCJS_FAST_WEAK
getFastWeakTicket w = do
r <- js_weakTicket w
case js_isNull r of
True -> return Nothing
False -> return $ Just $ FastWeakTicket r
foreign import javascript unsafe "$r = $1.ticket;" js_weakTicket :: FastWeak a -> IO JSVal
#else
getFastWeakTicket w = do
deRefWeak w >>= \case
Nothing -> return Nothing
Just v -> return $ Just $ FastWeakTicket
{ _fastWeakTicket_val = v
, _fastWeakTicket_weak = w
}
#endif
mkFastWeakTicket :: a -> IO (FastWeakTicket a)
#ifdef GHCJS_FAST_WEAK
mkFastWeakTicket v = js_fastWeakTicket (unsafeToRawJSVal v)
foreign import javascript unsafe "$r = new h$FastWeakTicket($1);" js_fastWeakTicket :: JSVal -> IO (FastWeakTicket a)
#else
mkFastWeakTicket v = do
v' <- evaluate v
w <- mkWeakPtr v' Nothing
return $ FastWeakTicket
{ _fastWeakTicket_val = v'
, _fastWeakTicket_weak = w
}
#endif
getFastWeakTicketWeak :: FastWeakTicket a -> IO (FastWeak a)
#ifdef GHCJS_FAST_WEAK
foreign import javascript unsafe "$r = $1.weak;" getFastWeakTicketWeak' :: FastWeakTicket a -> IO (FastWeak a)
{-# INLINE getFastWeakTicketWeak #-}
getFastWeakTicketWeak = getFastWeakTicketWeak'
#else
getFastWeakTicketWeak = return . _fastWeakTicket_weak
#endif
emptyFastWeak :: FastWeak a
emptyFastWeak = unsafeCoerce w
where w :: FastWeak Any
#ifdef GHCJS_FAST_WEAK
w = js_emptyWeak
#else
w = unsafePerformIO $ do
w' <- mkWeakPtr undefined Nothing
finalize w'
return w'
#endif
{-# NOINLINE emptyFastWeak #-}
#ifdef GHCJS_FAST_WEAK
foreign import javascript unsafe "$r = new h$FastWeak(null);" js_emptyWeak :: FastWeak Any
#endif