module Hans.Layer where
import Hans.Utils (just)
import Control.Applicative (Applicative(..),Alternative(..))
import Control.Monad (ap,MonadPlus(mzero,mplus))
import Data.Monoid (Monoid(..))
import Data.Time.Clock.POSIX
import MonadLib (StateM(get,set),BaseM(inBase))
import qualified Control.Exception as X
import qualified Data.Map as Map
data LayerState i = LayerState
{ lsNow :: POSIXTime
, lsState :: i
}
data Action = Nop | Action (IO ())
instance Monoid Action where
mempty = Nop
mappend (Action a) (Action b) = Action (a >> b)
mappend Nop b = b
mappend a _ = a
runAction :: Action -> IO ()
runAction Nop = return ()
runAction (Action m) = m `X.catch` \ se -> print (se :: X.SomeException)
data Result i a
= Error Action
| Exit (LayerState i) Action
| Result (LayerState i) a Action
type Exit i r = LayerState i -> Action -> Result i r
type Failure i r = Action -> Result i r
type Success a i r = a -> LayerState i -> Action -> Result i r
newtype Layer i a = Layer
{ getLayer :: forall r. LayerState i
-> Action
-> Exit i r
-> Failure i r
-> Success a i r
-> Result i r }
runLayer :: LayerState i -> Layer i a -> Result i a
runLayer i0 m = getLayer m i0 mempty Exit Error success
where success a i o = Result i a o
loopLayer :: String -> i -> IO msg -> (msg -> Layer i ()) -> IO ()
loopLayer name i0 msg k =
loop (LayerState 0 i0) `X.finally` putStrLn (name ++ " died")
where
loop i = do
a <- msg
now <- getPOSIXTime
let res = runLayer (i {lsNow = now }) (k a)
_ <- X.evaluate res `X.catch` \ se -> do
putStrLn (name ++ show (se :: X.SomeException))
return res
case res of
Error m -> runAction m >> loop i
Exit i' m -> runAction m >> loop i'
Result i' () m -> runAction m >> loop i'
instance Functor (Layer i) where
fmap g m = Layer $ \i0 o0 x f k ->
getLayer m i0 o0 x f (\a i o -> k (g a) i o)
instance Applicative (Layer i) where
pure = return
(<*>) = ap
instance Alternative (Layer i) where
empty = Layer (\_ o0 _ f _ -> f o0)
a <|> b = Layer (\i o x f k -> getLayer a i o x (\_ -> getLayer b i o x f k) k)
instance Monad (Layer i) where
return a = Layer (\i o _ _ k -> k a i o)
m >>= g = Layer $ \i0 o0 x f k -> getLayer m i0 o0 x f $ \a i o ->
getLayer (g a) i o x f k
instance MonadPlus (Layer i) where
mzero = empty
mplus = (<|>)
instance StateM (Layer i) i where
get = Layer (\i0 o0 _ _ k -> k (lsState i0) i0 o0)
set i = Layer (\i0 o0 _ _ k -> k () (i0 { lsState = i }) o0)
instance BaseM (Layer i) (Layer i) where
inBase = id
finish :: Layer i a
finish = Layer (\i o x _ _ -> x i o)
dropPacket :: Layer i a
dropPacket = finish
time :: Layer i POSIXTime
time = Layer (\i o _ _ k -> k (lsNow i) i o)
output :: IO () -> Layer i ()
output m = Layer $ \i0 o0 _ _ k -> k () i0 (o0 `mappend` Action m)
liftRight :: Either String b -> Layer i b
liftRight (Right b) = return b
liftRight (Left err) = do
output (putStrLn err)
dropPacket
type Handlers k a = Map.Map k a
emptyHandlers :: Handlers k a
emptyHandlers = Map.empty
class ProvidesHandlers i k a | i -> k a where
getHandlers :: i -> Handlers k a
setHandlers :: Handlers k a -> i -> i
getHandler :: (Ord k, ProvidesHandlers i k a) => k -> Layer i a
getHandler k = do
state <- get
just (Map.lookup k (getHandlers state))
addHandler :: (Ord k, ProvidesHandlers i k a) => k -> a -> Layer i ()
addHandler k a = do
state <- get
let hs' = Map.insert k a (getHandlers state)
hs' `seq` set (setHandlers hs' state)
removeHandler :: (Ord k, ProvidesHandlers i k a) => k -> Layer i ()
removeHandler k = do
state <- get
let hs' = Map.delete k (getHandlers state)
hs' `seq` set (setHandlers hs' state)