packages feed

vision-0.0.2.2: src/Handler.hs

-- -*-haskell-*-
--  Vision (for the Voice): an XMMS2 client.
--
--  Author:  Oleg Belozeorov
--  Created: 11 Jun. 2010
--
--  Copyright (C) 2010 Oleg Belozeorov
--
--  This program is free software; you can redistribute it and/or
--  modify it under the terms of the GNU General Public License as
--  published by the Free Software Foundation; either version 3 of
--  the License, or (at your option) any later version.
--
--  This program is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
--  General Public License for more details.
--

module Handler
  ( Id
  , Handler
  , make
  , add
  , remove
  , invoke
  , once
  , ever
  , keep
  ) where

import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Data.Foldable


data Id m a = Id Int

type Entry m a = (Int, a -> m Bool)
type Entries m a = IntMap (Entry m a)

data Handler m a
  = Handler { nextId  :: Id m a
            , entries :: Entries m a
            }

make :: Handler m a
make = Handler { nextId = Id 0, entries = IntMap.empty }

add :: Monad m => (a -> m Bool) -> Handler m a -> m (Handler m a, Id m a)
add f Handler { nextId = id@(Id n), entries = e } =
  return (h, id)
  where h = Handler { nextId   = Id $ succ n
                    , entries = IntMap.insert n (n, f) e
                    }

remove :: Monad m => Id m a -> Handler m a -> m (Handler m a, ())
remove (Id n) h =
  return (h { entries = IntMap.delete n $ entries h }, ())

invoke :: Monad m => a -> Handler m a -> m (Handler m a, ())
invoke a h@Handler { entries = e } = do
  e' <- foldlM (invoke' a) e e
  return (h { entries = e' }, ())
  where invoke' a e (i, f) = do
          p <- f a
          if p
            then return e
            else return $ IntMap.delete i e

once :: Monad m => (a -> m b) -> a -> m Bool
once = keep False

ever :: Monad m => (a -> m b) -> a -> m Bool
ever = keep True

keep :: Monad m => Bool -> (a -> m b) -> a -> m Bool
keep r f a = f a >> return r