packages feed

StateVar 1.0.1.1 → 1.2.2

raw patch · 5 files changed

Files

+ CHANGELOG.md view
@@ -0,0 +1,55 @@+1.2.2+-----+* Relaxed upper version bound for `transformers`.++1.2.1+-----+* Explicitly mark `Data.StateVar` as Safe (or Trustworthy for GHC before 7.10).++1.2+---+* Added instances for `ForeignPtr`.++1.1.1.1+-------+* Relaxed upper version bound for `stm`.++1.1.1.0+-------+* Track recent move of `Contravariant` to `base`.++1.1.0.4+-------+* Corrected HasUpdate's superclass constraint.++1.1.0.3+-------+* Removed a couple of redundant typeclass constraints.++1.1.0.2+-------+* Relaxed upper version bound for `transformers`.++1.1.0.1+-------+* Documentation changes only.++1.1.0.0+-------+* Melded the API of `foreign-var` 0.1 with the API of `StateVar` 1.0.1.1+* Introduced `HasUpdate`, which permits a wider array of uses of these combinators, including usecases that must update atomically.+* Switched to multi-parameter typeclasses. This permits `Ptr a` to be directly employed as an instance of `HasGetter`, `HasUpdate`, and `HasSetter`.++1.0.1.1+-------+* Infrastructure changes only.++1.0.1.0+-------+* Exposed `GettableStateVar`, `SettableStateVar` and `StateVar` constructors to make writing own instances possible.+* Added `Functor`, `Applicative` and `Monad` instances for `GettableStateVar`.+* Various infrastructure improvements.++1.0.0.0+-------+* Initial release.
LICENSE view
@@ -1,4 +1,5 @@-Copyright (c) 2009, Sven Panne+Copyright (c) 2014-2015, Edward Kmett+Copyright (c) 2009-2021, Sven Panne All rights reserved.  Redistribution and use in source and binary forms, with or without
+ README.md view
@@ -0,0 +1,4 @@+[![Hackage](https://img.shields.io/hackage/v/StateVar.svg)](https://hackage.haskell.org/package/StateVar)+[![Stackage LTS](https://www.stackage.org/package/StateVar/badge/lts)](https://www.stackage.org/lts/package/StateVar)+[![Stackage nightly](https://www.stackage.org/package/StateVar/badge/nightly)](https://www.stackage.org/nightly/package/StateVar)+[![Build Status](https://img.shields.io/travis/haskell-opengl/StateVar/master.svg)](https://travis-ci.org/haskell-opengl/StateVar)
StateVar.cabal view
@@ -1,25 +1,68 @@ name: StateVar-version: 1.0.1.1+version: 1.2.2 synopsis: State variables description:   This package contains state variables, which are references in the IO monad,   like IORefs or parts of the OpenGL state. homepage: https://github.com/haskell-opengl/StateVar bug-reports: https://github.com/haskell-opengl/StateVar/issues+copyright: Copyright (C) 2014-2015 Edward A. Kmett, 2009-2021 Sven Panne license: BSD3 license-file: LICENSE-author: Sven Panne+author: Sven Panne and Edward Kmett maintainer: Sven Panne <svenpanne@gmail.com> category: Data build-type: Simple-cabal-version: >=1.10+tested-with:+  GHC == 7.0.4+  GHC == 7.2.2+  GHC == 7.4.2+  GHC == 7.6.3+  GHC == 7.8.4+  GHC == 7.10.3+  GHC == 8.0.2+  GHC == 8.2.2+  GHC == 8.4.3+  GHC == 8.6.5+  GHC == 8.8.4+  GHC == 8.10.3+  GHC == 8.10.4+  GHC == 9.0.1+cabal-version: >= 1.10+extra-source-files:+  README.md+  CHANGELOG.md  library-  exposed-modules: Data.StateVar-  build-depends: base >= 3 && < 5+  exposed-modules:+    Data.StateVar++  build-depends:+    base         >= 4   && < 5,+    stm          >= 2.3.0.1 && < 2.6,+    transformers >= 0.3 && < 0.7+   default-language: Haskell2010-  hs-Source-Dirs: src+  other-extensions:+    CPP+    DeriveDataTypeable+    MultiParamTypeClasses+    FunctionalDependencies+    FlexibleInstances+    TypeFamilies++  hs-source-dirs: src   ghc-options: -Wall+  if impl(ghc > 8)+    ghc-options: -Wcompat+  if impl(ghc>=7.4)+    -- other-extensions: DefaultSignatures+    cpp-options: -DUSE_DEFAULT_SIGNATURES=1++  if impl(ghc >= 9.0)+    -- these flags may abort compilation with GHC-8.10+    -- https://gitlab.haskell.org/ghc/ghc/-/merge_requests/3295+    ghc-options: -Winferred-safe-imports -Wmissing-safe-haskell-mode  source-repository head   type: git
src/Data/StateVar.hs view
@@ -1,7 +1,22 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE FlexibleInstances #-}+#if USE_DEFAULT_SIGNATURES+{-# LANGUAGE DefaultSignatures #-}+#endif+{-# LANGUAGE TypeFamilies #-}+-- Foreign.ForeignPtr is unsafe before GHC-7.10+#if __GLASGOW_HASKELL__ >= 704 && MIN_VERSION_base(4,8,0)+{-# LANGUAGE Safe #-}+#elif __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif -------------------------------------------------------------------------------- -- | -- Module      :  Data.StateVar--- Copyright   :  (c) Sven Panne 2014+-- Copyright   :  (c) Edward Kmett 2014-2019, Sven Panne 2009-2021 -- License     :  BSD3 --  -- Maintainer  :  Sven Panne <svenpanne@gmail.com>@@ -12,7 +27,7 @@ -- the OpenGL state. Note that state variables are not neccessarily writable or -- readable, they may come in read-only or write-only flavours, too. As a very -- simple example for a state variable, consider an explicitly allocated memory--- buffer. This buffer can easily be converted into a 'StateVar':+-- buffer. This buffer could easily be converted into a 'StateVar': -- -- @ -- makeStateVarFromPtr :: Storable a => Ptr a -> StateVar a@@ -32,6 +47,16 @@ --      print x -- @ --+-- However, 'Ptr' can be used directly through the same API:+--+-- @+--   do p <- malloc :: IO (Ptr Int)+--      p $= 11+--      p $~ (+ 22)+--      x <- get p+--      print x+-- @+-- -- 'IORef's are state variables, too, so an example with them looks extremely -- similiar: --@@ -44,117 +69,237 @@ -- @ -------------------------------------------------------------------------------- -module Data.StateVar (-   -- * Readable State Variables-   HasGetter(..),-   GettableStateVar(..), makeGettableStateVar,-   -- * Writable State Variables-   HasSetter(..),-   SettableStateVar(..), makeSettableStateVar,-   -- * General State Variables-   StateVar(..), makeStateVar,-   -- * Utility Functions-   ($~), ($=!), ($~!)-) where+module Data.StateVar+  (+  -- * Readable State Variables+    HasGetter(get)+  , GettableStateVar, makeGettableStateVar+  -- * Writable State Variables+  , HasSetter(($=)), ($=!)+  , SettableStateVar(SettableStateVar), makeSettableStateVar+  -- * Updatable State Variables+  , HasUpdate(($~), ($~!))+  , StateVar(StateVar), makeStateVar+  , mapStateVar+  ) where -import Control.Applicative ( Applicative(..) )-import Data.IORef ( IORef, readIORef, writeIORef )+import Control.Concurrent.STM+import Control.Monad.IO.Class+import Data.IORef+import Data.Typeable+import Foreign.ForeignPtr+import Foreign.Ptr+import Foreign.Storable+#if MIN_VERSION_base(4,12,0)+import Data.Functor.Contravariant+#endif ---------------------------------------------------------------------------------+--------------------------------------------------------------------+-- * StateVar+-------------------------------------------------------------------- -infixr 2 $=+-- | A concrete implementation of a readable and writable state variable,+-- carrying one IO action to read the value and another IO action to write the+-- new value. This data type represents a piece of mutable, imperative state+-- with possible side-effects. These tend to encapsulate all sorts tricky+-- behavior in external libraries, and may well throw exceptions. Inhabitants+-- __should__ satsify the following properties:+--+-- * In the absence of concurrent mutation from other threads or a thrown+-- exception:+--+-- @+-- do x <- 'get' v; v '$=' y; v '$=' x+-- @+--+-- should restore the previous state.+--+-- * Ideally, in the absence of thrown exceptions:+--+-- @+-- v '$=' a >> 'get' v+-- @+--+-- should return @a@, regardless of @a@. In practice some 'StateVar's only+-- permit a very limited range of value assignments, and do not report failure.+data StateVar a = StateVar (IO a) (a -> IO ()) deriving Typeable ---------------------------------------------------------------------------------+#if MIN_VERSION_base(4,12,0)+instance Contravariant SettableStateVar where+  contramap f (SettableStateVar k) = SettableStateVar (k . f)+  {-# INLINE contramap #-}+#endif --- | The class of all readable state variables.-class HasGetter g where-   -- | Read the value of a state variable.-   get :: g a -> IO a+-- | Construct a 'StateVar' from two IO actions, one for reading and one for+--- writing.+makeStateVar+  :: IO a         -- ^ getter+  -> (a -> IO ()) -- ^ setter+  -> StateVar a+makeStateVar = StateVar -instance HasGetter IORef where-   get = readIORef+-- | Change the type of a 'StateVar'+mapStateVar :: (b -> a) -> (a -> b) -> StateVar a -> StateVar b+mapStateVar ba ab (StateVar ga sa) = StateVar (fmap ab ga) (sa . ba)+{-# INLINE mapStateVar #-} --- | A concrete implementation of a read-only state variable, carrying an IO+-- | A concrete implementation of a write-only state variable, carrying an IO+-- action to write the new value.+newtype SettableStateVar a = SettableStateVar (a -> IO ())+  deriving Typeable++-- | Construct a 'SettableStateVar' from an IO action for writing.+makeSettableStateVar+  :: (a -> IO ()) -- ^ setter+  -> SettableStateVar a+makeSettableStateVar = SettableStateVar+{-# INLINE makeSettableStateVar #-}++-- | A concrete implementation of a read-only state variable is simply an IO -- action to read the value.-newtype GettableStateVar a = GettableStateVar (IO a)+type GettableStateVar = IO -instance HasGetter GettableStateVar where-   get (GettableStateVar g) = g+-- | Construct a 'GettableStateVar' from an IO action.+makeGettableStateVar+  :: IO a -- ^ getter+  -> GettableStateVar a+makeGettableStateVar = id+{-# INLINE makeGettableStateVar #-} -instance Functor GettableStateVar where-  fmap f (GettableStateVar g) = GettableStateVar (fmap f g)+--------------------------------------------------------------------+-- * HasSetter+-------------------------------------------------------------------- -instance Applicative GettableStateVar where-  pure = GettableStateVar . pure-  GettableStateVar g <*> GettableStateVar h = GettableStateVar (g <*> h)+infixr 2 $=, $=! -instance Monad GettableStateVar where-  return = pure-  GettableStateVar g >>= h = GettableStateVar (g >>= get . h)+-- | This is the class of all writable state variables.+class HasSetter t a | t -> a where+  -- | Write a new value into a state variable.+  ($=) :: MonadIO m => t -> a -> m () --- | Construct a 'GettableStateVar' from an IO action.-makeGettableStateVar :: IO a -> GettableStateVar a-makeGettableStateVar = GettableStateVar+-- | This is a variant of '$=' which is strict in the value to be set.+($=!) :: (HasSetter t a, MonadIO m) => t -> a -> m ()+p $=! a = (p $=) $! a+{-# INLINE ($=!) #-} ---------------------------------------------------------------------------------+instance HasSetter (SettableStateVar a) a where+  SettableStateVar f $= a = liftIO (f a)+  {-# INLINE ($=) #-} --- | The class of all writable state variables.-class HasSetter s where-   -- | Write a new value into a state variable.-   ($=) :: s a -> a -> IO ()+instance HasSetter (StateVar a) a where+  StateVar _ s $= a = liftIO $ s a+  {-# INLINE ($=) #-} -instance HasSetter IORef where-   ($=) = writeIORef+instance Storable a => HasSetter (Ptr a) a where+  p $= a = liftIO $ poke p a+  {-# INLINE ($=) #-} --- | A concrete implementation of a write-only state variable, carrying an IO--- action to write the new value.-newtype SettableStateVar a = SettableStateVar (a -> IO ())+instance HasSetter (IORef a) a where+  p $= a = liftIO $ writeIORef p a+  {-# INLINE ($=) #-} -instance HasSetter SettableStateVar where-   ($=) (SettableStateVar s) a = s a+instance HasSetter (TVar a) a where+  p $= a = liftIO $ atomically $ writeTVar p a+  {-# INLINE ($=) #-} --- instance Contravariant SettableStateVar where---    contramap f (SettableStateVar s) = SettableStateVar (s . f)+instance Storable a => HasSetter (ForeignPtr a) a where+  p $= a = liftIO $ withForeignPtr p ($= a)+  {-# INLINE ($=) #-} --- | Construct a 'SettableStateVar' from an IO action.-makeSettableStateVar :: (a -> IO ()) -> SettableStateVar a-makeSettableStateVar = SettableStateVar+--------------------------------------------------------------------+-- * HasUpdate+-------------------------------------------------------------------- ---------------------------------------------------------------------------------+infixr 2 $~, $~! --- | A concrete implementation of a readable and writable state variable,--- carrying one IO action to read the value and another IO action to write the--- new value.-data StateVar a =-   StateVar (GettableStateVar a) (SettableStateVar a)+-- | This is the class of all updatable state variables.+class HasSetter t b => HasUpdate t a b | t -> a b where+  -- | Transform the contents of a state variable with a given funtion.+  ($~) :: MonadIO m => t -> (a -> b) -> m ()+#if USE_DEFAULT_SIGNATURES+  default ($~) :: (MonadIO m, a ~ b, HasGetter t a) => t -> (a -> b) -> m ()+  ($~) = defaultUpdate+#endif+  -- | This is a variant of '$~' which is strict in the transformed value.+  ($~!) :: MonadIO m => t -> (a -> b) -> m ()+#if USE_DEFAULT_SIGNATURES+  default ($~!) :: (MonadIO m, a ~ b, HasGetter t a) => t -> (a -> b) -> m ()+  ($~!) = defaultUpdateStrict+#endif -instance HasGetter StateVar where-   get (StateVar g _) = get g+defaultUpdate :: (MonadIO m, a ~ b, HasGetter t a, HasSetter t a) => t -> (a -> b) -> m ()+defaultUpdate r f = liftIO $ do+  a <- get r+  r $= f a -instance HasSetter StateVar where-   ($=) (StateVar _ s) a = s $= a+defaultUpdateStrict :: (MonadIO m, a ~ b, HasGetter t a, HasSetter t a) => t -> (a -> b) -> m ()+defaultUpdateStrict r f = liftIO $ do+  a <- get r+  r $=! f a --- | Construct a 'StateVar' from two IO actions, one for reading and one for--- writing.-makeStateVar :: IO a -> (a -> IO ()) -> StateVar a-makeStateVar g s = StateVar (makeGettableStateVar g) (makeSettableStateVar s)+instance HasUpdate (StateVar a) a a where+  ($~) = defaultUpdate+  ($~!) = defaultUpdateStrict ---------------------------------------------------------------------------------+instance Storable a => HasUpdate (Ptr a) a a where+  ($~) = defaultUpdate+  ($~!) = defaultUpdateStrict --- | A modificator convenience function, transforming the contents of a state--- variable with a given funtion.+instance HasUpdate (IORef a) a a where+  r $~ f  = liftIO $ atomicModifyIORef r $ \a -> (f a,())+#if MIN_VERSION_base(4,6,0)+  r $~! f = liftIO $ atomicModifyIORef' r $ \a -> (f a,())+#else+  r $~! f = liftIO $ do+    s <- atomicModifyIORef r $ \a -> let s = f a in (s, s)+    s `seq` return ()+#endif -($~) :: (HasGetter v, HasSetter v) => v a -> (a -> a) -> IO ()-v $~ f = do-   x <- get v-   v $= f x+instance HasUpdate (TVar a) a a where+  r $~ f = liftIO $ atomically $ do+    a <- readTVar r+    writeTVar r (f a)+  r $~! f = liftIO $ atomically $ do+    a <- readTVar r+    writeTVar r $! f a --- | A variant of '$=' which is strict in the value to be set.-($=!) :: HasSetter s => s a -> a -> IO ()-v $=! x = x `seq` v $= x+instance Storable a => HasUpdate (ForeignPtr a) a a where+  p $~ f = liftIO $ withForeignPtr p ($~ f)+  p $~! f = liftIO $ withForeignPtr p ($~! f) --- | A variant of '$~' which is strict in the transformed value.-($~!) :: (HasGetter v, HasSetter v) => v a -> (a -> a) -> IO ()-v $~! f = do-   x <- get v-   v $=! f x+--------------------------------------------------------------------+-- * HasGetter+--------------------------------------------------------------------++-- | This is the class of all readable state variables.+class HasGetter t a | t -> a where+  get :: MonadIO m => t -> m a++instance HasGetter (StateVar a) a where+  get (StateVar g _) = liftIO g+  {-# INLINE get #-}++instance HasGetter (TVar a) a where+  get = liftIO . atomically . readTVar+  {-# INLINE get #-}++instance HasGetter (IO a) a where+  get = liftIO+  {-# INLINE get #-}++instance HasGetter (STM a) a where+  get = liftIO . atomically+  {-# INLINE get #-}++instance Storable a => HasGetter (Ptr a) a where+  get = liftIO . peek+  {-# INLINE get #-}++instance HasGetter (IORef a) a where+  get = liftIO . readIORef+  {-# INLINE get #-}++instance Storable a => HasGetter (ForeignPtr a) a where+  get p = liftIO $ withForeignPtr p get+  {-# INLINE get #-}+