@@ -22,6 +22,7 @@ module Roboservant.StateMachine
25+import Control.Monad (guard)
25import Control.Monad.IO.Class (MonadIO, liftIO)
26import Control.Monad.IO.Class (MonadIO, liftIO)
26import Data.Dynamic (Dynamic, dynApply, dynTypeRep, fromDynamic)
27import Data.Dynamic (Dynamic, dynApply, dynTypeRep, fromDynamic)
27import Data.IORef (IORef, newIORef)
28import Data.IORef (IORef, newIORef)
@@ -42,13 +43,12 @@ import Type.Reflection (SomeTypeRep)
42callEndpoint :: (MonadGen n, MonadIO m) => ReifiedApi -> Command n m State
43callEndpoint :: (MonadGen n, MonadIO m) => ReifiedApi -> Command n m State
43callEndpoint staticRoutes =
44callEndpoint staticRoutes =
44 let gen :: MonadGen n => State Symbolic -> Maybe (n (Op Symbolic))
45 let gen :: MonadGen n => State Symbolic -> Maybe (n (Op Symbolic))
45− gen State {..} = case preloads of
46+ gen State {..} = case chewable of
46− (v : _) -> Just $ pure $ Preload (dynTypeRep v) v
47+ -- Chewable values still need to be broken down.
48+ (c : _) -> Just $ pure $ Chewable c
48− if any null options
50+ guard $ not $ null options
51− uncurry Op <$> chooseOne options
51+ pure $ uncurry Op <$> chooseOne options
53 chooseOne ::
53 chooseOne ::
54 MonadGen n =>
54 MonadGen n =>
@@ -76,7 +76,9 @@ callEndpoint staticRoutes =
76 (MonadIO m) =>
76 (MonadIO m) =>
77 Op Concrete ->
77 Op Concrete ->
78 m (Opaque (IORef Dynamic))
78 m (Opaque (IORef Dynamic))
79+ -- bit subtle here - a chewable v _also_ gets a var, because chewing it should
80+ -- only give subcomponents.
79− execute (Preload _tr v) = Opaque <$> liftIO (newIORef v)
81+ execute (Chewable v) = Opaque <$> liftIO (newIORef v)
80 execute (Op (ApiOffset offset) args) = do
82 execute (Op (ApiOffset offset) args) = do
81 fmap Opaque . liftIO $ do
83 fmap Opaque . liftIO $ do
82 realArgs <- mapM (readIORef . opaque) args
84 realArgs <- mapM (readIORef . opaque) args
@@ -98,12 +100,13 @@ callEndpoint staticRoutes =
99 [ Update $ \s@State {..} op o' ->
101 [ Update $ \s@State {..} op o' ->
100 case op of
102 case op of
101− Preload tr _v ->
103+ Chewable v ->
104+ let (c : cs) = chewable
103− { stateRefs =
106+ { stateRefs =
104− Map.insertWith (<>) tr (pure o') stateRefs,
107+ Map.insertWith (<>) (dynTypeRep v) (pure o') stateRefs,
105− preloads = drop 1 preloads
108+ chewable = (breakdownDynamic c) <> cs
107 (Op (ApiOffset offset) _args) ->
110 (Op (ApiOffset offset) _args) ->
109 { stateRefs =
112 { stateRefs =
@@ -116,6 +119,11 @@ callEndpoint staticRoutes =
122+-- | just a stub for now - this is where we probably have to start using ConstrainedDynamic
123+-- so we can pack them in with a Breakdown constraint. TODO.
124+breakdownDynamic :: Dynamic -> [Dynamic]
125+breakdownDynamic = const []
119prop_sequential :: forall api. (FlattenServer api, ToReifiedApi (Endpoints api)) => Server api -> [Dynamic] -> PropertyT IO ()
127prop_sequential :: forall api. (FlattenServer api, ToReifiedApi (Endpoints api)) => Server api -> [Dynamic] -> PropertyT IO ()
120prop_sequential server seed = do
128prop_sequential server seed = do
121 let reifiedApi = toReifiedApi (flattenServer @api server) (Proxy @(Endpoints api))
129 let reifiedApi = toReifiedApi (flattenServer @api server) (Proxy @(Endpoints api))
@@ -123,9 +131,9 @@ prop_sequential server seed = do
123 forAll $ do
131 forAll $ do
124 Gen.sequential
132 Gen.sequential
125 (Range.linear 1 100)
133 (Range.linear 1 100)
126− (State mempty seed)
134+ (emptyState {chewable = seed})
127 [callEndpoint reifiedApi]
135 [callEndpoint reifiedApi]
128− executeSequential (State mempty seed) actions
136+ executeSequential (emptyState {chewable = seed}) actions
130prop_concurrent :: forall api. (FlattenServer api, ToReifiedApi (Endpoints api)) => Server api -> [Dynamic] -> PropertyT IO ()
138prop_concurrent :: forall api. (FlattenServer api, ToReifiedApi (Endpoints api)) => Server api -> [Dynamic] -> PropertyT IO ()
131prop_concurrent server seed =
139prop_concurrent server seed =
@@ -136,7 +144,7 @@ prop_concurrent server seed =
136 Gen.parallel
144 Gen.parallel
137 (Range.linear 1 50)
145 (Range.linear 1 50)
138 (Range.linear 1 10)
146 (Range.linear 1 10)
139− (State mempty seed)
147+ (emptyState {chewable = seed})
140 [callEndpoint reifiedApi]
148 [callEndpoint reifiedApi]
142− executeParallel (State mempty seed) actions
150+ executeParallel (emptyState {chewable = seed}) actions