From 7d25114b6f59b1a3c913b5cf886ae66316f06ea8 Mon Sep 17 00:00:00 2001 From: Jens Nolte <git@queezle.net> Date: Wed, 26 Aug 2020 23:42:00 +0200 Subject: [PATCH] Remove timestamp from ObservableState --- src/lib/Qd/Observable.hs | 62 ++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/src/lib/Qd/Observable.hs b/src/lib/Qd/Observable.hs index 5eb95dd..983916e 100644 --- a/src/lib/Qd/Observable.hs +++ b/src/lib/Qd/Observable.hs @@ -1,45 +1,40 @@ module Qd.Observable ( - Observable, + Observable(..), IsObservable(..), subscribe', - SubscriptionHandle, - unsubscribe, + SubscriptionHandle(..), Callback, ObservableState, ObservableMessage, MessageReason(..), - - BasicObservable(..), - Freshness(..), + BasicObservable, mkBasicObservable, - staleBasicObservable, + setBasicObservable, updateBasicObservable, ) where import Control.Concurrent.MVar import Control.Monad.Fix (mfix) +import Data.Binary (Binary) import qualified Data.HashMap.Strict as HM -import Data.Time.Clock (UTCTime, getCurrentTime) import Data.Unique +import GHC.Generics (Generic) -data Freshness = Fresh | Stale - deriving (Eq, Show) 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) mapObservableState :: Monad m => (a -> m b) -> ObservableState a -> m (ObservableState b) 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 f (r, s) = (r, ) <$> mapObservableState f s -newtype SubscriptionHandle = SubscriptionHandle (IO ()) -unsubscribe :: SubscriptionHandle -> IO () -unsubscribe (SubscriptionHandle unsubscribeAction) = unsubscribeAction +newtype SubscriptionHandle = SubscriptionHandle { unsubscribe :: IO () } class IsObservable v o | o -> v where getValue :: o -> IO (ObservableState v) @@ -62,6 +57,13 @@ instance IsObservable v (Observable v) where instance Functor Observable where 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))) instance IsObservable v (BasicObservable v) where getValue (BasicObservable mvar) = fst <$> readMVar mvar @@ -78,26 +80,18 @@ instance IsObservable v (BasicObservable v) where mkBasicObservable :: Maybe v -> IO (BasicObservable v) mkBasicObservable defaultValue = do - now <- getCurrentTime - BasicObservable <$> newMVar ((, Fresh, now) <$> defaultValue, HM.empty) + BasicObservable <$> newMVar (defaultValue, HM.empty) -staleBasicObservable :: BasicObservable v -> IO () -staleBasicObservable (BasicObservable mvar) = do - modifyMVar_ mvar $ \(oldState, subscribers) -> do - let newState = (\(v, _, t) -> (v, Stale, t)) <$> oldState +setBasicObservable :: BasicObservable v -> v -> IO () +setBasicObservable (BasicObservable mvar) value = do + modifyMVar_ mvar $ \(_, subscribers) -> do + let newState = Just value mapM_ (\callback -> callback (Update, newState)) subscribers return (newState, subscribers) -updateBasicObservable :: forall v. BasicObservable v -> Maybe v -> IO () -updateBasicObservable (BasicObservable mvar) value = do - now <- getCurrentTime - let newState = (, Fresh, now) <$> value - modifyMVar_ mvar $ \(state, subscribers) -> do - mapM_ (\callback -> callback (Update, state)) subscribers +updateBasicObservable :: BasicObservable v -> (v -> v) -> IO () +updateBasicObservable (BasicObservable mvar) f = + modifyMVar_ mvar $ \(oldState, subscribers) -> do + let newState = (\v -> f v) <$> oldState + mapM_ (\callback -> callback (Update, 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 -- GitLab