packages feed

unliftio 0.2.2.0 → 0.2.4.0

raw patch · 12 files changed

+195/−81 lines, 12 filesdep ~unliftio-corePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: unliftio-core

API changes (from Hackage documentation)

+ UnliftIO.IO: getMonotonicTime :: MonadIO m => m Double

Files

ChangeLog.md view
@@ -1,3 +1,8 @@+## 0.2.3.0++* Use more generalized `withRunInIO` in `unliftio-core-0.1.1.0`+* Add `getMonotonicTime` function+ ## 0.2.2.0  * Add `pureTry` and `pureTryDeep`
README.md view
@@ -188,37 +188,23 @@ applying `run` as necessary. `withRunIO` takes care of invoking `unliftIO` for us. -However, if we want to use the run function with different types, we-must use `askUnliftIO`:--```haskell-race :: MonadUnliftIO m => m a -> m b -> m (Either a b)-race a b = do-  u <- askUnliftIO-  liftIO (A.race (unliftIO u a) (unliftIO u b))-```--or more idiomatically `withUnliftIO`:+We can also use the run function with different types due to+`withRunInIO` being higher-rank polymorphic:  ```haskell race :: MonadUnliftIO m => m a -> m b -> m (Either a b)-race a b = withUnliftIO $ \u -> A.race (unliftIO u a) (unliftIO u b)+race a b = withRunInIO $ \run -> A.race (run a) (run b) ``` -This works just like `withRunIO`, except we use `unliftIO u` instead-of `run`, which is polymorphic. You _could_ get away with multiple-`withRunInIO` calls here instead, but this approach is idiomatic and-may be more performant (depending on optimizations).- And finally, a more complex usage, when unlifting the `mask`-function. This function needs to unlift vaues to be passed into the+function. This function needs to unlift values to be passed into the `restore` function, and then `liftIO` the result of the `restore` function.  ```haskell mask :: MonadUnliftIO m => ((forall a. m a -> m a) -> m b) -> m b-mask f = withUnliftIO $ \u -> Control.Exception.mask $ \unmask ->-  unliftIO u $ f $ liftIO . unmask . unliftIO u+mask f = withRunInIO $ \run -> Control.Exception.mask $ \restore ->+  run $ f $ liftIO . restore . run ```  ## Limitations
+ cbits/time-osx.c view
@@ -0,0 +1,20 @@+/* From https://github.com/bos/criterion */++#include <mach/mach.h>+#include <mach/mach_time.h>++static mach_timebase_info_data_t timebase_info;+static double timebase_recip;++void unliftio_inittime(void)+{+    if (timebase_recip == 0) {+	mach_timebase_info(&timebase_info);+	timebase_recip = (timebase_info.denom / timebase_info.numer) / 1e9;+    }+}++double unliftio_gettime(void)+{+    return mach_absolute_time() * timebase_recip;+}
+ cbits/time-posix.c view
@@ -0,0 +1,16 @@+/* From https://github.com/bos/criterion */++#include <time.h>++void unliftio_inittime(void)+{+}++double unliftio_gettime(void)+{+    struct timespec ts;++    clock_gettime(CLOCK_MONOTONIC, &ts);++    return ts.tv_sec + ts.tv_nsec * 1e-9;+}
+ cbits/time-windows.c view
@@ -0,0 +1,41 @@+/* From https://github.com/bos/criterion */++/*+ * Windows has the most amazingly cretinous time measurement APIs you+ * can possibly imagine.+ *+ * Our first possibility is GetSystemTimeAsFileTime, which updates at+ * roughly 60Hz, and is hence worthless - we'd have to run a+ * computation for tens or hundreds of seconds to get a trustworthy+ * number.+ *+ * Alternatively, we can use QueryPerformanceCounter, which has+ * undefined behaviour under almost all interesting circumstances+ * (e.g. multicore systems, CPU frequency changes). But at least it+ * increments reasonably often.+ */++#include <windows.h>++static double freq_recip;+static LARGE_INTEGER firstClock;++void unliftio_inittime(void)+{+    LARGE_INTEGER freq;++    if (freq_recip == 0) {+	QueryPerformanceFrequency(&freq);+	QueryPerformanceCounter(&firstClock);+	freq_recip = 1.0 / freq.QuadPart;+    }+}++double unliftio_gettime(void)+{+    LARGE_INTEGER li;++    QueryPerformanceCounter(&li);++    return ((double) (li.QuadPart - firstClock.QuadPart)) * freq_recip;+}
src/UnliftIO.hs view
@@ -1,3 +1,5 @@+-- | Please see the README.md file for information on using this+-- package at <https://www.stackage.org/package/unliftio>. module UnliftIO   ( module Control.Monad.IO.Unlift   , module UnliftIO.Async
src/UnliftIO/Async.hs view
@@ -85,32 +85,32 @@ -- @since 0.1.0.0 asyncWithUnmask :: MonadUnliftIO m => ((forall b. m b -> m b) -> m a) -> m (Async a) asyncWithUnmask m =-  withUnliftIO $ \u -> A.asyncWithUnmask $ \unmask -> unliftIO u $ m $ liftIO . unmask . unliftIO u+  withRunInIO $ \run -> A.asyncWithUnmask $ \unmask -> run $ m $ liftIO . unmask . run  -- | Unlifted 'A.asyncOnWithUnmask'. -- -- @since 0.1.0.0 asyncOnWithUnmask :: MonadUnliftIO m => Int -> ((forall b. m b -> m b) -> m a) -> m (Async a) asyncOnWithUnmask i m =-  withUnliftIO $ \u -> A.asyncOnWithUnmask i $ \unmask -> unliftIO u $ m $ liftIO . unmask . unliftIO u+  withRunInIO $ \run -> A.asyncOnWithUnmask i $ \unmask -> run $ m $ liftIO . unmask . run  -- | Unlifted 'A.withAsync'. -- -- @since 0.1.0.0 withAsync :: MonadUnliftIO m => m a -> (Async a -> m b) -> m b-withAsync a b = withUnliftIO $ \u -> A.withAsync (unliftIO u a) (unliftIO u . b)+withAsync a b = withRunInIO $ \run -> A.withAsync (run a) (run . b)  -- | Unlifted 'A.withAsyncBound'. -- -- @since 0.1.0.0 withAsyncBound :: MonadUnliftIO m => m a -> (Async a -> m b) -> m b-withAsyncBound a b = withUnliftIO $ \u -> A.withAsyncBound (unliftIO u a) (unliftIO u . b)+withAsyncBound a b = withRunInIO $ \run -> A.withAsyncBound (run a) (run . b)  -- | Unlifted 'A.withAsyncOn'. -- -- @since 0.1.0.0 withAsyncOn :: MonadUnliftIO m => Int -> m a -> (Async a -> m b) -> m b-withAsyncOn i a b = withUnliftIO $ \u -> A.withAsyncOn i (unliftIO u a) (unliftIO u . b)+withAsyncOn i a b = withRunInIO $ \run -> A.withAsyncOn i (run a) (run . b)  -- | Unlifted 'A.withAsyncWithUnmask'. --@@ -121,9 +121,9 @@   -> (Async a -> m b)   -> m b withAsyncWithUnmask a b =-  withUnliftIO $ \u -> A.withAsyncWithUnmask-    (\unmask -> unliftIO u $ a $ liftIO . unmask . unliftIO u)-    (unliftIO u . b)+  withRunInIO $ \run -> A.withAsyncWithUnmask+    (\unmask -> run $ a $ liftIO . unmask . run)+    (run . b)  -- | Unlifted 'A.withAsyncOnWithMask'. --@@ -135,9 +135,9 @@   -> (Async a -> m b)   -> m b withAsyncOnWithUnmask i a b =-  withUnliftIO $ \u -> A.withAsyncOnWithUnmask i-    (\unmask -> unliftIO u $ a $ liftIO . unmask . unliftIO u)-    (unliftIO u . b)+  withRunInIO $ \run -> A.withAsyncOnWithUnmask i+    (\unmask -> run $ a $ liftIO . unmask . run)+    (run . b)  -- | Lifted 'A.wait'. --@@ -252,25 +252,25 @@ -- -- @since 0.1.0.0 race :: MonadUnliftIO m => m a -> m b -> m (Either a b)-race a b = withUnliftIO $ \u -> A.race (unliftIO u a) (unliftIO u b)+race a b = withRunInIO $ \run -> A.race (run a) (run b)  -- | Unlifted 'A.race_'. -- -- @since 0.1.0.0 race_ :: MonadUnliftIO m => m a -> m b -> m ()-race_ a b = withUnliftIO $ \u -> A.race_ (unliftIO u a) (unliftIO u b)+race_ a b = withRunInIO $ \run -> A.race_ (run a) (run b)  -- | Unlifted 'A.concurrently'. -- -- @since 0.1.0.0 concurrently :: MonadUnliftIO m => m a -> m b -> m (a, b)-concurrently a b = withUnliftIO $ \u -> A.concurrently (unliftIO u a) (unliftIO u b)+concurrently a b = withRunInIO $ \run -> A.concurrently (run a) (run b)  -- | Unlifted 'A.concurrently_'. -- -- @since 0.1.0.0 concurrently_ :: MonadUnliftIO m => m a -> m b -> m ()-concurrently_ a b = withUnliftIO $ \u -> A.concurrently_ (unliftIO u a) (unliftIO u b)+concurrently_ a b = withRunInIO $ \run -> A.concurrently_ (run a) (run b)  -- | Unlifted 'A.mapConcurrently'. --
src/UnliftIO/Concurrent.hs view
@@ -63,14 +63,14 @@ -- @since 0.1.1.0 forkWithUnmask :: MonadUnliftIO m => ((forall a. m a -> m a) -> m ()) -> m ThreadId forkWithUnmask m =-  withUnliftIO $ \u -> C.forkIOWithUnmask $ \unmask -> unliftIO u $ m $ liftIO . unmask . unliftIO u+  withRunInIO $ \run -> C.forkIOWithUnmask $ \unmask -> run $ m $ liftIO . unmask . run {-# INLINABLE forkWithUnmask #-}  -- | Unlifted version of 'C.forkFinally'. -- -- @since 0.1.1.0 forkFinally :: MonadUnliftIO m => m a -> (Either SomeException a -> m ()) -> m ThreadId-forkFinally m1 m2 = withUnliftIO $ \u -> C.forkFinally (unliftIO u m1) $ unliftIO u . m2+forkFinally m1 m2 = withRunInIO $ \run -> C.forkFinally (run m1) $ run . m2 {-# INLINABLE forkFinally #-}  -- | Lifted version of 'C.killThread'.@@ -92,7 +92,7 @@ -- @since 0.1.1.0 forkOnWithUnmask :: MonadUnliftIO m => Int -> ((forall a. m a -> m a) -> m ()) -> m ThreadId forkOnWithUnmask i m =-  withUnliftIO $ \u -> C.forkOnWithUnmask i $ \unmask -> unliftIO u $ m $ liftIO . unmask . unliftIO u+  withRunInIO $ \run -> C.forkOnWithUnmask i $ \unmask -> run $ m $ liftIO . unmask . run {-# INLINABLE forkOnWithUnmask #-}  -- | Lifted version of 'C.getNumCapabilities'.
src/UnliftIO/Exception.hs view
@@ -101,9 +101,9 @@ -- -- @since 0.1.0.0 catch :: (MonadUnliftIO m, Exception e) => m a -> (e -> m a) -> m a-catch f g = withUnliftIO $ \u -> unliftIO u f `EUnsafe.catch` \e ->+catch f g = withRunInIO $ \run -> run f `EUnsafe.catch` \e ->   if isSyncException e-    then unliftIO u (g e)+    then run (g e)     -- intentionally rethrowing an async exception synchronously,     -- since we want to preserve async behavior     else EUnsafe.throwIO e@@ -274,9 +274,9 @@ -- -- @since 0.1.0.0 bracket :: MonadUnliftIO m => m a -> (a -> m b) -> (a -> m c) -> m c-bracket before after thing = withUnliftIO $ \u -> EUnsafe.mask $ \restore -> do-  x <- unliftIO u before-  res1 <- EUnsafe.try $ restore $ unliftIO u $ thing x+bracket before after thing = withRunInIO $ \run -> EUnsafe.mask $ \restore -> do+  x <- run before+  res1 <- EUnsafe.try $ restore $ run $ thing x   case res1 of     Left (e1 :: SomeException) -> do       -- explicitly ignore exceptions from after. We know that@@ -285,10 +285,10 @@       --       -- https://github.com/fpco/safe-exceptions/issues/2       _ :: Either SomeException b <--          EUnsafe.try $ EUnsafe.uninterruptibleMask_ $ unliftIO u $ after x+          EUnsafe.try $ EUnsafe.uninterruptibleMask_ $ run $ after x       EUnsafe.throwIO e1     Right y -> do-      _ <- EUnsafe.uninterruptibleMask_ $ unliftIO u $ after x+      _ <- EUnsafe.uninterruptibleMask_ $ run $ after x       return y  -- | Async safe version of 'EUnsafe.bracket_'.@@ -301,14 +301,14 @@ -- -- @since 0.1.0.0 bracketOnError :: MonadUnliftIO m => m a -> (a -> m b) -> (a -> m c) -> m c-bracketOnError before after thing = withUnliftIO $ \u -> EUnsafe.mask $ \restore -> do-  x <- unliftIO u before-  res1 <- EUnsafe.try $ restore $ unliftIO u $ thing x+bracketOnError before after thing = withRunInIO $ \run -> EUnsafe.mask $ \restore -> do+  x <- run before+  res1 <- EUnsafe.try $ restore $ run $ thing x   case res1 of     Left (e1 :: SomeException) -> do       -- ignore the exception, see bracket for explanation       _ :: Either SomeException b <--        EUnsafe.try $ EUnsafe.uninterruptibleMask_ $ unliftIO u $ after x+        EUnsafe.try $ EUnsafe.uninterruptibleMask_ $ run $ after x       EUnsafe.throwIO e1     Right y -> return y @@ -323,15 +323,15 @@ -- -- @since 0.1.0.0 finally :: MonadUnliftIO m => m a -> m b -> m a-finally thing after = withUnliftIO $ \u -> EUnsafe.uninterruptibleMask $ \restore -> do-  res1 <- EUnsafe.try $ restore $ unliftIO u thing+finally thing after = withRunInIO $ \run -> EUnsafe.uninterruptibleMask $ \restore -> do+  res1 <- EUnsafe.try $ restore $ run thing   case res1 of     Left (e1 :: SomeException) -> do       -- see bracket for explanation-      _ :: Either SomeException b <- EUnsafe.try $ unliftIO u after+      _ :: Either SomeException b <- EUnsafe.try $ run after       EUnsafe.throwIO e1     Right x -> do-      _ <- unliftIO u after+      _ <- run after       return x  -- | Like 'onException', but provides the handler the thrown@@ -340,12 +340,12 @@ -- @since 0.1.0.0 withException :: (MonadUnliftIO m, Exception e)               => m a -> (e -> m b) -> m a-withException thing after = withUnliftIO $ \u -> EUnsafe.uninterruptibleMask $ \restore -> do-    res1 <- EUnsafe.try $ restore $ unliftIO u thing+withException thing after = withRunInIO $ \run -> EUnsafe.uninterruptibleMask $ \restore -> do+    res1 <- EUnsafe.try $ restore $ run thing     case res1 of         Left e1 -> do             -- see explanation in bracket-            _ :: Either SomeException b <- EUnsafe.try $ unliftIO u $ after e1+            _ :: Either SomeException b <- EUnsafe.try $ run $ after e1             EUnsafe.throwIO e1         Right x -> return x @@ -462,15 +462,15 @@ -- -- @since 0.1.0.0 mask :: MonadUnliftIO m => ((forall a. m a -> m a) -> m b) -> m b-mask f = withUnliftIO $ \u -> EUnsafe.mask $ \unmask ->-  unliftIO u $ f $ liftIO . unmask . unliftIO u+mask f = withRunInIO $ \run -> EUnsafe.mask $ \unmask ->+  run $ f $ liftIO . unmask . run  -- | Unlifted version of 'EUnsafe.uninterruptibleMask'. -- -- @since 0.1.0.0 uninterruptibleMask :: MonadUnliftIO m => ((forall a. m a -> m a) -> m b) -> m b-uninterruptibleMask f = withUnliftIO $ \u -> EUnsafe.uninterruptibleMask $ \unmask ->-  unliftIO u $ f $ liftIO . unmask . unliftIO u+uninterruptibleMask f = withRunInIO $ \run -> EUnsafe.uninterruptibleMask $ \unmask ->+  run $ f $ liftIO . unmask . run  -- | Unlifted version of 'EUnsafe.mask_'. --
src/UnliftIO/IO.hs view
@@ -30,12 +30,15 @@   , hGetEcho   , hWaitForInput   , hReady+  , getMonotonicTime   ) where  import qualified System.IO as IO import System.IO (Handle, IOMode (..)) import Control.Monad.IO.Unlift +import System.IO.Unsafe (unsafePerformIO)+ -- | Unlifted version of 'IO.withFile'. -- -- @since 0.1.0.0@@ -161,3 +164,19 @@ -- @since 0.2.1.0 hReady :: MonadIO m => Handle -> m Bool hReady = liftIO . IO.hReady++-- | Get the number of seconds which have passed since an arbitrary starting+-- time, useful for calculating runtime in a program.+--+-- @since 0.2.3.0+getMonotonicTime :: MonadIO m => m Double+getMonotonicTime = liftIO $ initted `seq` getMonotonicTime'++-- | Set up time measurement.+foreign import ccall unsafe "unliftio_inittime" initializeTime :: IO ()++initted :: ()+initted = unsafePerformIO initializeTime+{-# NOINLINE initted #-}++foreign import ccall unsafe "unliftio_gettime" getMonotonicTime' :: IO Double
+ test/UnliftIO/IOSpec.hs view
@@ -0,0 +1,14 @@+module UnliftIO.IOSpec (spec) where++import Test.Hspec+import UnliftIO.IO+import Control.Concurrent (threadDelay)++spec :: Spec+spec = do+  describe "getMonotonicTime" $ do+    it "increases" $ do+      x <- getMonotonicTime+      threadDelay 5000+      y <- getMonotonicTime+      y - x `shouldSatisfy` (>= 5e-3)
unliftio.cabal view
@@ -1,11 +1,11 @@--- This file has been generated from package.yaml by hpack version 0.20.0.+-- This file has been generated from package.yaml by hpack version 0.21.2. -- -- see: https://github.com/sol/hpack ----- hash: 5a724f566f49e39a6208566cbc3e42117113cd8c19867e2f53151c8022d9919b+-- hash: 1bad09ed70712d36c4a392da05c02952b932befd883b7013501c876023f34cf2  name:           unliftio-version:        0.2.2.0+version:        0.2.4.0 synopsis:       The MonadUnliftIO typeclass for unlifting monads to IO (batteries included) description:    Please see the documentation and README at <https://www.stackage.org/package/unliftio> category:       Control@@ -23,20 +23,6 @@     README.md  library-  hs-source-dirs:-      src-  build-depends:-      async >2.1.1-    , base >=4.7 && <5-    , deepseq-    , directory-    , filepath-    , stm >=2.4.3-    , transformers-    , unliftio-core-  if !os(Windows)-    build-depends:-        unix   exposed-modules:       UnliftIO       UnliftIO.Async@@ -51,11 +37,39 @@       UnliftIO.Timeout   other-modules:       Paths_unliftio+  hs-source-dirs:+      src+  build-depends:+      async >2.1.1+    , base >=4.7 && <5+    , deepseq+    , directory+    , filepath+    , stm >=2.4.3+    , transformers+    , unliftio-core >=0.1.1.0+  if !os(Windows)+    build-depends:+        unix+  if os(darwin)+    c-sources:+        cbits/time-osx.c+  else+    if os(windows)+      c-sources:+          cbits/time-windows.c+    else+      c-sources:+          cbits/time-posix.c   default-language: Haskell2010  test-suite unliftio-spec   type: exitcode-stdio-1.0   main-is: Spec.hs+  other-modules:+      UnliftIO.ExceptionSpec+      UnliftIO.IOSpec+      Paths_unliftio   hs-source-dirs:       test   build-depends:@@ -68,11 +82,8 @@     , stm >=2.4.3     , transformers     , unliftio-    , unliftio-core+    , unliftio-core >=0.1.1.0   if !os(Windows)     build-depends:         unix-  other-modules:-      UnliftIO.ExceptionSpec-      Paths_unliftio   default-language: Haskell2010