packages feed

bluefin-internal 0.9.1.0 → 0.9.2.0

raw patch · 6 files changed

+56/−14 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Bluefin.Internal.Vault: delete :: Key a -> Vault -> Vault

Files

CHANGELOG.md view
@@ -1,3 +1,11 @@+# 0.9.2.0++* Bug fix: release `Reader` Vault keys when their handler scope exits.++* Make `Vault`'s `Key` type role representational.  This is+  technically a PVP violation but since it's fixing a type safety bug+  we're not going to release a major version for it.+ # 0.9.1.0  * Add `yieldToPureList`
bluefin-internal.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               bluefin-internal-version:            0.9.1.0+version:            0.9.2.0 license:            MIT license-file:       LICENSE author:             Tom Ellis
src/Bluefin/Internal.hs view
@@ -22,8 +22,8 @@     oneWayCoercion,     trans3D,     unsafeCoercionOfOneWayCoercion,-    unsafeOneWayCoercible,     unsafeOneWayCoerce,+    unsafeOneWayCoercible,   ) import Bluefin.Internal.Vault (Vault) import Bluefin.Internal.Vault qualified as Vault@@ -1656,11 +1656,14 @@   (forall e. Reader r e -> Eff (e :& es) a) ->   Eff es a runReader r f = do-  k <- UnsafeMkEff $ \vault -> do-    k <- Vault.newKey-    modifyIORef' vault (\v -> Vault.insert k r v)-    pure k-  makeOp (f (MkReader k))+  bracket+    ( UnsafeMkEff $ \vault -> do+        k <- Vault.newKey+        modifyIORef' vault (\v -> Vault.insert k r v)+        pure k+    )+    (\k -> UnsafeMkEff $ \vault -> modifyIORef' vault (Vault.delete k))+    (\k -> makeOp (f (MkReader k)))  -- | Read the value.  Note that @ask@ has the property that these two -- operations are always equivalent:
src/Bluefin/Internal/CloneableHandle.hs view
@@ -117,10 +117,10 @@  hcHandleReader :: (CloneableHandle h) => HandleCloner (HandleReader h) (HandleReader h) e hcHandleReader = MkHandleCloner $ \hr k -> do-  h <- askHandle hr-  cloneHandleClass h $ \h' -> do-    runHandleReader h' $ \hr' -> do-      useImplIn k (mapHandle hr')+  asksHandle hr $ \h -> do+    cloneHandleClass h $ \h' -> do+      runHandleReader h' $ \hr' -> do+        useImplIn k (mapHandle hr')  instance   (TypeError (Text "Coroutine cannot be cloned. Perhaps you want an STM channel?")) =>
src/Bluefin/Internal/Vault.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE RoleAnnotations #-}+ module Bluefin.Internal.Vault   ( module Bluefin.Internal.Vault,     Vault,@@ -18,6 +20,8 @@ type Key :: Type -> Type newtype Key a = MkKey (Vault.Key Any) +type role Key representational+ fromMine :: Key a -> Vault.Key a fromMine (MkKey k) = unsafeCoerce k @@ -35,3 +39,6 @@  insert :: Key a -> a -> Vault -> Vault insert = Vault.insert . fromMine++delete :: Key a -> Vault -> Vault+delete = Vault.delete . fromMine
test/Main.hs view
@@ -4,8 +4,11 @@ module Main (main) where  import Bluefin.Internal+import Bluefin.Internal.Vault qualified as Vault import Control.Monad (forever, when) import Data.Foldable (for_)+import Data.IORef (readIORef)+import Data.Maybe (isNothing) import Test.GeneralBracket (test_generalBracket) import Test.SpecH (SpecH, assertEqual, runSpecH) import Prelude hiding (break, read)@@ -44,6 +47,7 @@       ([20, 30], "Hello")      test_localInHandler y+    test_readerCleanup y     test_generalBracket io y     test_streamConsumeReader y     test_streamConsumeHandleReader y@@ -94,6 +98,26 @@   for_ as (yield y)   pure r +test_readerCleanup :: (e <: es) => SpecH e -> Eff es ()+test_readerCleanup y = runReader @Int 1 $ \outer -> do+  for_ [False, True] $ \abort -> do+    key <- withEarlyReturn $ \ex ->+      runReader @Int 2 $ \(MkReader key) ->+        if abort then returnEarly ex key else pure key+    do+      -- Use the internals to check a property that cannot be tested without them.+      cleanedUp <- UnsafeMkEff $ \vault -> do+        contents <- readIORef vault+        pure (isNothing (Vault.lookup key contents))+      assertEqual+        y+        "Reader key released on normal and exceptional exit"+        True+        cleanedUp+    do+      outerValue <- ask outer+      assertEqual y "Outer Reader survives inner cleanup" 1 outerValue+ test_localInHandler :: (e <: es) => SpecH e -> Eff es () test_localInHandler y = runReader "global" $ \re ->   forEach@@ -143,7 +167,7 @@       )  -- localHandle run in one branch of a streamConsume should not affect--- askHandle in the other branch.+-- asksHandle in the other branch. test_streamConsumeHandleReader :: (e <: es) => SpecH e -> Eff es () test_streamConsumeHandleReader spech = do   runConstEffect @Int 0 $ \ce ->@@ -152,8 +176,8 @@         ( \y -> do             let s = yield y ()             let check i = do-                  MkConstEffect i' <- askHandle r-                  assertEqual spech "HandleReader local" i i'+                  asksHandle r $ \(MkConstEffect i') -> do+                    assertEqual spech "HandleReader local" i i'             check 0             s             check 0