module Data.RangeMin.Fusion.Stream (
	Stream,
	MStream,
	length,
	liftStream,
	imap,
	generate,
	enumN,
	iunfoldN,
	imapM_,
	snoc,
	imapAccumL,
	ifoldl,
	fromListN) where

import qualified Data.RangeMin.Fusion.Stream.Monadic as SM
import Data.RangeMin.Common.Types
import Data.RangeMin.Common.Combinators

import Data.Vector.Fusion.Util

import Prelude hiding (map, length)

type Stream = SM.Stream Id
type MStream = SM.Stream

{-# INLINE length #-}
length :: Stream a -> Int
length = SM.length

{-# INLINE liftStream #-}
liftStream :: Monad m => Stream a -> SM.Stream m a
liftStream (SM.Stream suc s0 n) = SM.Stream (\ i a -> return (unId (suc i a))) s0 n

{-# INLINE imap #-}
imap :: (Index -> a -> b) -> Stream a -> Stream b
imap f = SM.imapM (return .: f)

{-# INLINE generate #-}
generate :: Length -> (Index -> a) -> Stream a
generate n f = SM.generateM n (return . f)

{-# INLINE enumN #-}
enumN :: Length -> Stream Int
enumN n = generate n id

{-# INLINE iunfoldN #-}
iunfoldN :: Length -> (Index -> b -> Maybe (a, b)) -> b -> Stream a
iunfoldN n f = SM.iunfoldMN n (return .: f)

{-# INLINE imapM_ #-}
imapM_ :: Monad m => (Index -> a -> m b) -> Stream a -> m ()
imapM_ f str = SM.imapM_ f (liftStream str)

{-# INLINE snoc #-}
snoc :: Stream a -> a -> Stream a
stream `snoc` x = stream `SM.snocM` return x

{-# INLINE imapAccumL #-}
imapAccumL :: (b -> Index -> a -> (c, b)) -> b -> Stream a -> Stream c
imapAccumL f = SM.imapAccumLM (\ z i a -> return (f z i a))

{-# INLINE ifoldl #-}
ifoldl :: (b -> Index -> a -> b) -> b -> Stream a -> b
ifoldl f z s = unId (SM.ifoldlM (\ z i a -> return (f z i a)) z s)

{-# INLINE fromListN #-}
fromListN :: Length -> [a] -> Stream a
fromListN = SM.fromListN