-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/

-- | A basic library for rate-limiting IO actions.
--   
--   In many cases, it is useful, necessary, or simply nice to limit how
--   frequently you perform some action. For example, you may want to limit
--   how often your program makes a request of some web site. This library
--   is intended as a general-purpose mechanism for rate-limiting IO
--   actions.
@package rate-limit
@version 1.4.3

-- | This module implements rate-limiting functionality for Haskell
--   programs. Rate-limiting is useful when trying to control / limit
--   access to a particular resource over time. For example, you might want
--   to limit the rate at which you make requests to a server, as an
--   administrator may block your access if you make too many requests too
--   quickly. Similarly, one may wish to rate-limit certain communication
--   actions, in order to avoid accidentally performing a denial-of-service
--   attack on a critical resource.
--   
--   The fundamental idea of this library is that given some basic
--   information about the requests you wante rate limited, it will return
--   you a function that hides all the rate-limiting detail. In short, you
--   make a call to one of the function generators in this file, and you
--   will be returned a function to use. For example:
--   
--   
--   do f <- generateRateLimitedFunction ...
--      ...
--      res1 <- f a
--      ...
--      res2 <- f b
--      ...
--   
--   
--   The calls to the generated function (f) will be rate limited based on
--   the parameters given to generateRateLimitedFunction.
--   
--   generateRateLimitedFunction is the most general version of the
--   rate limiting functionality, but specialized versions of it are also
--   exported for convenience.
module Control.RateLimit

-- | The most generic way to rate limit an invocation.
generateRateLimitedFunction :: forall req resp t. TimeUnit t => RateLimit t -> (req -> IO resp) -> ResultsCombiner req resp -> IO (req -> IO resp)

-- | The rate at which to limit an action.
data RateLimit a

-- | Rate limit the action to invocation once per time unit. With this
--   option, the time it takes for the action to take place is not taken
--   into consideration when computing the rate, only the time between
--   invocations of the action. This may cause the action to execute
--   concurrently, as an invocation may occur while an action is still
--   running.
PerInvocation :: a -> RateLimit a

-- | Rate limit the action to execution once per time unit. With this
--   option, the time it takes for the action to take plase is taken into
--   account, and all actions will necessarily occur sequentially. However,
--   if your action takes longer than the time unit given, then the rate of
--   execution will be slower than the given unit of time.
PerExecution :: a -> RateLimit a

-- | In some cases, if two requests are waiting to be run, it may be
--   possible to combine them into a single request and thus increase the
--   overall bandwidth. The rate limit system supports this, but requires a
--   little additional information to make everything work out right. You
--   may also need to do something a bit wonky with your types to make this
--   work ... sorry.
--   
--   The basic idea is this: Given two requests, you can either return
--   Nothing (signalling that the two requests can be combined), or a Just
--   with a new request representing the combination of the two requests.
--   In addition, you will need to provide a function that can turn the
--   response to this single request into two responses, one for each of
--   the original requests.
--   
--   I hope this description helps you work through the type, which I'll
--   admit is a bit opaque.
type ResultsCombiner req resp = req -> req -> Maybe (req, resp -> (resp, resp))
dontCombine :: ResultsCombiner a b

-- | Rate limit the invocation of a given action. This is equivalent to
--   calling generateRateLimitedFunction with a PerInvocation
--   rate limit and the dontCombine combining function.
rateLimitInvocation :: TimeUnit t => t -> (req -> IO resp) -> IO (req -> IO resp)

-- | Rate limit the execution of a given action. This is equivalent to
--   calling generateRateLimitedFunction with a PerExecution
--   rate limit and the dontCombine combining function.
rateLimitExecution :: TimeUnit t => t -> (req -> IO resp) -> IO (req -> IO resp)
