-- | Helper functions for turnings streams into vectors.
--
-- Mostly very similar to bundle conversion functions from the @vector@
-- package.

module Data.Vector.Generic.Unstream where

import           Control.Monad.ST
import           GHC.Conc (pseq)
import qualified Data.Vector.Fusion.Stream.Monadic as SM
import qualified Data.Vector.Generic as VG
import qualified Data.Vector.Generic.Mutable as VGM
import           System.IO.Unsafe (unsafePerformIO)

-- for testing

import qualified Data.Vector.Unboxed as VU



-- | Turns a stream into a vector.
--
-- TODO insert index checks? Generalized @flag devel@

streamToVectorM :: forall m v a . (Monad m, VG.Vector v a) => SM.Stream m a -> m (v a)
streamToVectorM s = do
  let mv' = unsafePerformIO $ VGM.unsafeNew 1
  let put (v',i) x =
        do let v = unsafePerformIO $ if (i < VGM.length v') then return v' else VGM.unsafeGrow v' (max 1 $ VGM.length v')
           seq (unsafePerformIO $ VGM.unsafeWrite v i x) (return (v,i+1))
      {-# Inline [0] put #-}
  (mv,written) <- SM.foldlM' put (mv',0) s
  mv `pseq` return . unsafePerformIO . VG.freeze $ VGM.unsafeSlice 0 written mv
{-# Inline streamToVectorM #-}