content: {- |
  Collect and process all incoming values statefully and with time stamps.
  -}
  module FRP.Rhine.ResamplingBuffer.ClSF where
  
  -- transformers
  import Control.Monad.Trans.Reader (ReaderT, runReaderT)
  
  -- automaton
  import Data.Automaton
  import Data.Stream
  import Data.Stream.Optimized (toStreamT)
  import Data.Stream.Result (mapResultState)
  
  -- rhine
  import FRP.Rhine.ClSF.Core
  import FRP.Rhine.ResamplingBuffer
  
  {- | Given a clocked signal function that accepts
     a varying number of timestamped inputs (a list),
     a `ResamplingBuffer` can be formed
     that collects all this input and steps the signal function
     whenever output is requested.
  -}
  clsfBuffer ::
    (Monad m) =>
    -- | The clocked signal function that consumes
    --   and a list of timestamped inputs,
    --   and outputs a single value.
    --   The list will contain the /newest/ element in the head.
    ClSF m cl2 [(TimeInfo cl1, a)] b ->
    ResamplingBuffer m cl1 cl2 a b
  clsfBuffer = clsfBuffer' . toStreamT . getAutomaton
    where
      clsfBuffer' ::
        (Monad m) =>
        StreamT (ReaderT [(TimeInfo cl1, a)] (ReaderT (TimeInfo cl2) m)) b ->
        ResamplingBuffer m cl1 cl2 a b
      clsfBuffer' StreamT {state, step} =
        ResamplingBuffer
          { buffer = (state, [])
          , put = \ti1 a (s, as) -> return (s, (ti1, a) : as)
          , get = \ti2 (s, as) -> mapResultState (,[]) <$> runReaderT (runReaderT (step s) as) ti2
          }
  