Skip to content
Snippets Groups Projects
Commit 7d25114b authored by Jens Nolte's avatar Jens Nolte
Browse files

Remove timestamp from ObservableState

parent 9f627199
No related branches found
No related tags found
No related merge requests found
module Qd.Observable ( module Qd.Observable (
Observable, Observable(..),
IsObservable(..), IsObservable(..),
subscribe', subscribe',
SubscriptionHandle, SubscriptionHandle(..),
unsubscribe,
Callback, Callback,
ObservableState, ObservableState,
ObservableMessage, ObservableMessage,
MessageReason(..), MessageReason(..),
BasicObservable,
BasicObservable(..),
Freshness(..),
mkBasicObservable, mkBasicObservable,
staleBasicObservable, setBasicObservable,
updateBasicObservable, updateBasicObservable,
) where ) where
import Control.Concurrent.MVar import Control.Concurrent.MVar
import Control.Monad.Fix (mfix) import Control.Monad.Fix (mfix)
import Data.Binary (Binary)
import qualified Data.HashMap.Strict as HM import qualified Data.HashMap.Strict as HM
import Data.Time.Clock (UTCTime, getCurrentTime)
import Data.Unique import Data.Unique
import GHC.Generics (Generic)
data Freshness = Fresh | Stale
deriving (Eq, Show)
data MessageReason = Current | Update data MessageReason = Current | Update
deriving (Eq, Show) deriving (Eq, Show, Generic)
instance Binary MessageReason
type ObservableState v = Maybe (v, Freshness, UTCTime) type ObservableState v = Maybe v
type ObservableMessage v = (MessageReason, ObservableState v) type ObservableMessage v = (MessageReason, ObservableState v)
mapObservableState :: Monad m => (a -> m b) -> ObservableState a -> m (ObservableState b) mapObservableState :: Monad m => (a -> m b) -> ObservableState a -> m (ObservableState b)
mapObservableState _ Nothing = return Nothing mapObservableState _ Nothing = return Nothing
mapObservableState f (Just (v, fr, t)) = Just . (, fr, t) <$> f v mapObservableState f (Just v) = Just <$> f v
mapObservableMessage :: Monad m => (a -> m b) -> ObservableMessage a -> m (ObservableMessage b) mapObservableMessage :: Monad m => (a -> m b) -> ObservableMessage a -> m (ObservableMessage b)
mapObservableMessage f (r, s) = (r, ) <$> mapObservableState f s mapObservableMessage f (r, s) = (r, ) <$> mapObservableState f s
newtype SubscriptionHandle = SubscriptionHandle (IO ()) newtype SubscriptionHandle = SubscriptionHandle { unsubscribe :: IO () }
unsubscribe :: SubscriptionHandle -> IO ()
unsubscribe (SubscriptionHandle unsubscribeAction) = unsubscribeAction
class IsObservable v o | o -> v where class IsObservable v o | o -> v where
getValue :: o -> IO (ObservableState v) getValue :: o -> IO (ObservableState v)
...@@ -62,6 +57,13 @@ instance IsObservable v (Observable v) where ...@@ -62,6 +57,13 @@ instance IsObservable v (Observable v) where
instance Functor Observable where instance Functor Observable where
fmap f = mapObservable (return . f) fmap f = mapObservable (return . f)
data MappedObservable b = forall a o. IsObservable a o => MappedObservable (a -> IO b) o
instance IsObservable v (MappedObservable v) where
getValue (MappedObservable f observable) = mapObservableState f =<< getValue observable
subscribe (MappedObservable f observable) callback = subscribe observable (callback <=< mapObservableMessage f)
mapObservable f1 (MappedObservable f2 upstream) = Observable $ MappedObservable (f1 <=< f2) upstream
newtype BasicObservable v = BasicObservable (MVar (ObservableState v, HM.HashMap Unique (Callback v))) newtype BasicObservable v = BasicObservable (MVar (ObservableState v, HM.HashMap Unique (Callback v)))
instance IsObservable v (BasicObservable v) where instance IsObservable v (BasicObservable v) where
getValue (BasicObservable mvar) = fst <$> readMVar mvar getValue (BasicObservable mvar) = fst <$> readMVar mvar
...@@ -78,26 +80,18 @@ instance IsObservable v (BasicObservable v) where ...@@ -78,26 +80,18 @@ instance IsObservable v (BasicObservable v) where
mkBasicObservable :: Maybe v -> IO (BasicObservable v) mkBasicObservable :: Maybe v -> IO (BasicObservable v)
mkBasicObservable defaultValue = do mkBasicObservable defaultValue = do
now <- getCurrentTime BasicObservable <$> newMVar (defaultValue, HM.empty)
BasicObservable <$> newMVar ((, Fresh, now) <$> defaultValue, HM.empty)
staleBasicObservable :: BasicObservable v -> IO () setBasicObservable :: BasicObservable v -> v -> IO ()
staleBasicObservable (BasicObservable mvar) = do setBasicObservable (BasicObservable mvar) value = do
modifyMVar_ mvar $ \(oldState, subscribers) -> do modifyMVar_ mvar $ \(_, subscribers) -> do
let newState = (\(v, _, t) -> (v, Stale, t)) <$> oldState let newState = Just value
mapM_ (\callback -> callback (Update, newState)) subscribers mapM_ (\callback -> callback (Update, newState)) subscribers
return (newState, subscribers) return (newState, subscribers)
updateBasicObservable :: forall v. BasicObservable v -> Maybe v -> IO () updateBasicObservable :: BasicObservable v -> (v -> v) -> IO ()
updateBasicObservable (BasicObservable mvar) value = do updateBasicObservable (BasicObservable mvar) f =
now <- getCurrentTime modifyMVar_ mvar $ \(oldState, subscribers) -> do
let newState = (, Fresh, now) <$> value let newState = (\v -> f v) <$> oldState
modifyMVar_ mvar $ \(state, subscribers) -> do mapM_ (\callback -> callback (Update, newState)) subscribers
mapM_ (\callback -> callback (Update, state)) subscribers
return (newState, subscribers) return (newState, subscribers)
data MappedObservable b = forall a o. IsObservable a o => MappedObservable (a -> IO b) o
instance IsObservable v (MappedObservable v) where
getValue (MappedObservable f observable) = mapObservableState f =<< getValue observable
subscribe (MappedObservable f observable) callback = subscribe observable (callback <=< mapObservableMessage f)
mapObservable f1 (MappedObservable f2 upstream) = Observable $ MappedObservable (f1 <=< f2) upstream
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment