@@ -5,6 +5,15 @@
55{-# LANGUAGE ForeignFunctionInterface #-}
66{-# LANGUAGE JavaScriptFFI #-}
77#endif
8+
9+-- | 'FastWeak' is a weak pointer to some value, and 'FastWeakTicket' ensures the value
10+-- referred to by a 'FastWeak' stays live while the ticket is held (live).
11+--
12+-- On GHC or GHCJS when not built with the @fast-weak@ cabal flag, 'FastWeak' is a wrapper
13+-- around the simple version of 'System.Mem.Weak.Weak' where the key and value are the same.
14+--
15+-- On GHCJS when built with the @fast-weak@ cabal flag, 'FastWeak' is implemented directly
16+-- in JS using @h$FastWeak@ and @h$FastWeakTicket@ which are a nonstandard part of the GHCJS RTS.
817module Reflex.FastWeak
918 ( FastWeakTicket
1019 , FastWeak
@@ -35,29 +44,57 @@ import System.Mem.Weak
3544
3645
3746#ifdef GHCJS_FAST_WEAK
47+-- | A 'FastWeak' which has been promoted to a strong reference. 'getFastWeakTicketValue'
48+-- can be used to get the referred to value without fear of @Nothing,
49+-- and 'getFastWeakTicketWeak' can be used to get the weak version.
50+--
51+-- Implemented by way of special support in the GHCJS RTS, @h$FastWeakTicket@.
3852newtype FastWeakTicket a = FastWeakTicket JSVal
3953
54+-- | A reference to some value which can be garbage collected if there are only
55+-- weak references to the value left.
56+--
57+-- 'getFastWeakValue' can be used to try and obtain a strong reference to the value.
58+--
59+-- The value in a @FastWeak@ can also be kept alive by obtaining a 'FastWeakTicket' using
60+-- 'getFastWeakTicket' if the value hasn't been collected yet.
61+--
62+-- Implemented by way of special support in the GHCJS RTS, @h$FastWeak@.
4063newtype FastWeak a = FastWeak JSVal
4164
4265-- Just designed to mirror JSVal, so that we can unsafeCoerce between the two
4366data Val a = Val { unVal :: a }
4467
45−-- | Coerce a JSVal that represents the heap object of a value of type 'a' into a value of type 'a'
68+-- | Coerce a JSVal that represents the heap object of a value of type @a@ into a value of type @a@
4669unsafeFromRawJSVal :: JSVal -> a
4770unsafeFromRawJSVal v = unVal (unsafeCoerce v)
4871
72+-- | Coerce a heap object of type @a@ into a 'JSVal' which represents that object.
4973unsafeToRawJSVal :: a -> JSVal
5074unsafeToRawJSVal v = unsafeCoerce (Val v)
5175#else
76+-- | A 'FastWeak' which has been promoted to a strong reference. 'getFastWeakTicketValue'
77+-- can be used to get the referred to value without fear of @Nothing@,
78+-- and 'getFastWeakTicketWeak' can be used to get the weak version.
5279data FastWeakTicket a = FastWeakTicket
5380 { _fastWeakTicket_val :: !a
5481 , _fastWeakTicket_weak :: {-# UNPACK #-} !(Weak a)
5582 }
5683
84+-- | A reference to some value which can be garbage collected if there are only weak references to the value left.
85+--
86+-- 'getFastWeakValue' can be used to try and obtain a strong reference to the value.
87+--
88+-- The value in a @FastWeak@ can also be kept alive by obtaining a 'FastWeakTicket' using 'getFastWeakTicket'
89+-- if the value hasn't been collected yet.
90+--
91+-- Synonymous with 'Weak'.
5792type FastWeak a = Weak a
5893#endif
5994
60−-- This needs to be in IO so we know that we've relinquished the ticket
95+-- | Return the @a@ kept alive by the given 'FastWeakTicket'.
96+--
97+-- This needs to be in IO so we know that we've relinquished the ticket.
6198getFastWeakTicketValue :: FastWeakTicket a -> IO a
6299#ifdef GHCJS_FAST_WEAK
63100getFastWeakTicketValue t = do
@@ -69,6 +106,8 @@ foreign import javascript unsafe "$r = $1.val;" js_ticketVal :: FastWeakTicket a
69106getFastWeakTicketValue = return . _fastWeakTicket_val
70107#endif
71108
109+-- | Get the value referred to by a 'FastWeak' if it hasn't yet been collected,
110+-- or @Nothing@ if it has been collected.
72111getFastWeakValue :: FastWeak a -> IO (Maybe a)
73112#ifdef GHCJS_FAST_WEAK
74113getFastWeakValue w = do
@@ -84,6 +123,9 @@ foreign import javascript unsafe "$r = ($1.ticket === null) ? null : $1.ticket.v
84123getFastWeakValue = deRefWeak
85124#endif
86125
126+-- | Try to create a 'FastWeakTicket' for the given 'FastWeak' which will ensure the value referred
127+-- remains alive. Returns @Just@ if the value hasn't been collected
128+-- and a ticket can therefore be obtained, @Nothing@ if it's been collected.
87129getFastWeakTicket :: forall a. FastWeak a -> IO (Maybe (FastWeakTicket a))
88130#ifdef GHCJS_FAST_WEAK
89131getFastWeakTicket w = do
@@ -103,8 +145,11 @@ getFastWeakTicket w = do
103145 }
104146#endif
105147
106−-- I think it's fine if this is lazy - it'll retain the 'a', but so would the output; we just need to make sure it's forced before we start relying on the associated FastWeak to actually be weak
148+-- | Create a 'FastWeakTicket' directly from a value, creating a 'FastWeak' in the process
149+-- which can be obtained with 'getFastWeakTicketValue'.
107150mkFastWeakTicket :: a -> IO (FastWeakTicket a)
151+-- I think it's fine if this is lazy - it'll retain the 'a', but so would the output; we just need to make sure it's forced before we start relying on the
152+-- associated FastWeak to actually be weak
108153#ifdef GHCJS_FAST_WEAK
109154mkFastWeakTicket v = js_fastWeakTicket (unsafeToRawJSVal v)
110155
@@ -119,11 +164,16 @@ mkFastWeakTicket v = do
119164 }
120165#endif
121166
167+-- | Demote a 'FastWeakTicket'; which ensures the value is alive, to a 'FastWeak' which doesn't.
168+-- Note that unless the ticket for the same 'FastWeak' is held in some other way
169+-- the value might be collected immediately.
170+getFastWeakTicketWeak :: FastWeakTicket a -> IO (FastWeak a)
122171-- Needs IO so that it can force the value - otherwise, could end up with a reference to the Ticket, which would retain the value
123172#ifdef GHCJS_FAST_WEAK
124−foreign import javascript unsafe "$r = $1.weak;" getFastWeakTicketWeak :: FastWeakTicket a -> IO (FastWeak a)
173+foreign import javascript unsafe "$r = $1.weak;" getFastWeakTicketWeak' :: FastWeakTicket a -> IO (FastWeak a)
174+{-# INLINE getFastWeakTicketWeak #-}
175+getFastWeakTicketWeak = getFastWeakTicketWeak'
125176#else
126−getFastWeakTicketWeak :: FastWeakTicket a -> IO (FastWeak a)
127177getFastWeakTicketWeak = return . _fastWeakTicket_weak
128178#endif
129179