-- | Debounce an action, ensuring it doesn't occur more than once for a given
-- period of time.
--
-- This is useful as an optimization, for example to ensure that logs are only
-- flushed to disk at most once per second.
--
-- Example usage:
--
-- @
-- > printString <- 'mkDebounce' 'defaultDebounceSettings'
--                  { 'debounceAction' = putStrLn "Running action"
--                  , 'debounceFreq' = 5000000 -- 5 seconds
--                  , 'debounceEdge' = 'DI.trailingEdge' -- Trigger on the trailing edge
--                  }
-- > printString
-- Running action
-- > printString
-- \<Wait five seconds>
-- Running action
-- @
--
-- See the fast-logger package ("System.Log.FastLogger") for real-world usage.
--
-- @since 0.1.2
module Control.Debounce (
    -- * Type
    DI.DebounceSettings,
    defaultDebounceSettings,

    -- * Accessors
    DI.debounceFreq,
    DI.debounceAction,
    DI.debounceEdge,
    DI.debounceThreadName,
    DI.leadingEdge,
    DI.trailingEdge,

    -- * Creation
    mkDebounce,
) where

import Control.Concurrent (newEmptyMVar, threadDelay)
import qualified Control.Debounce.Internal as DI

-- | Default value for creating a 'DebounceSettings'.
--
-- @since 0.1.2
defaultDebounceSettings :: DI.DebounceSettings
defaultDebounceSettings :: DebounceSettings
defaultDebounceSettings =
    DI.DebounceSettings
        { debounceFreq :: Int
DI.debounceFreq = Int
1000000
        , debounceAction :: IO ()
DI.debounceAction = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        , debounceEdge :: DebounceEdge
DI.debounceEdge = DebounceEdge
DI.leadingEdge
        , debounceThreadName :: String
DI.debounceThreadName = String
"Debounce"
        }

-- | Generate an action which will trigger the debounced action to be performed.
--
-- @since 0.1.2
mkDebounce :: DI.DebounceSettings -> IO (IO ())
mkDebounce :: DebounceSettings -> IO (IO ())
mkDebounce DebounceSettings
settings = do
    MVar ()
baton <- IO (MVar ())
forall a. IO (MVar a)
newEmptyMVar
    MVar () -> (Int -> IO ()) -> DebounceSettings -> IO (IO ())
DI.mkDebounceInternal MVar ()
baton Int -> IO ()
threadDelay DebounceSettings
settings