@@ -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,56 @@ 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' if the value hasn't been collected yet.
89+--
90+-- Synonymous with 'Weak'.
5791type FastWeak a = Weak a
5892#endif
5993
60−-- This needs to be in IO so we know that we've relinquished the ticket
94+-- | Return the @a@ kept alive by the given 'FastWeakTicket'.
95+--
96+-- This needs to be in IO so we know that we've relinquished the ticket.
6197getFastWeakTicketValue :: FastWeakTicket a -> IO a
6298#ifdef GHCJS_FAST_WEAK
6399getFastWeakTicketValue t = do
@@ -69,6 +105,8 @@ foreign import javascript unsafe "$r = $1.val;" js_ticketVal :: FastWeakTicket a
69105getFastWeakTicketValue = return . _fastWeakTicket_val
70106#endif
71107
108+-- | Get the value referred to by a 'FastWeak' if it hasn't yet been collected,
109+-- or @Nothing@ if it has been collected.
72110getFastWeakValue :: FastWeak a -> IO (Maybe a)
73111#ifdef GHCJS_FAST_WEAK
74112getFastWeakValue w = do
@@ -84,6 +122,9 @@ foreign import javascript unsafe "$r = ($1.ticket === null) ? null : $1.ticket.v
84122getFastWeakValue = deRefWeak
85123#endif
86124
125+-- | Try to create a 'FastWeakTicket' for the given 'FastWeak' which will ensure the value referred
126+-- remains alive. Returns @Just@ if the value hasn't been collected
127+-- and a ticket can therefore be obtained, @Nothing@ if it's been collected.
87128getFastWeakTicket :: forall a. FastWeak a -> IO (Maybe (FastWeakTicket a))
88129#ifdef GHCJS_FAST_WEAK
89130getFastWeakTicket w = do
@@ -103,8 +144,11 @@ getFastWeakTicket w = do
103144 }
104145#endif
105146
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
147+-- | Create a 'FastWeakTicket' directly from a value, creating a 'FastWeak' in the process
148+-- which can be obtained with 'getFastWeakTicketValue'.
107149mkFastWeakTicket :: a -> IO (FastWeakTicket a)
150+-- 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
151+-- associated FastWeak to actually be weak
108152#ifdef GHCJS_FAST_WEAK
109153mkFastWeakTicket v = js_fastWeakTicket (unsafeToRawJSVal v)
110154
@@ -119,11 +163,16 @@ mkFastWeakTicket v = do
119163 }
120164#endif
121165
166+-- | Demote a 'FastWeakTicket'; which ensures the value is alive, to a 'FastWeak' which doesn't.
167+-- Note that unless the ticket for the same 'FastWeak' is held in some other way
168+-- the value might be collected immediately.
169+getFastWeakTicketWeak :: FastWeakTicket a -> IO (FastWeak a)
122170-- Needs IO so that it can force the value - otherwise, could end up with a reference to the Ticket, which would retain the value
123171#ifdef GHCJS_FAST_WEAK
124−foreign import javascript unsafe "$r = $1.weak;" getFastWeakTicketWeak :: FastWeakTicket a -> IO (FastWeak a)
172+foreign import javascript unsafe "$r = $1.weak;" getFastWeakTicketWeak' :: FastWeakTicket a -> IO (FastWeak a)
173+{-# INLINE getFastWeakTicketWeak #-}
174+getFastWeakTicketWeak = getFastWeakTicketWeak'
125175#else
126−getFastWeakTicketWeak :: FastWeakTicket a -> IO (FastWeak a)
127176getFastWeakTicketWeak = return . _fastWeakTicket_weak
128177#endif
129178