{-# LANGUAGE BangPatterns, ExistentialQuantification #-}
-- |
-- Module      : Data.Text.Internal.Fusion.Types
-- Copyright   : (c) Tom Harper 2008-2009,
--               (c) Bryan O'Sullivan 2009,
--               (c) Duncan Coutts 2009,
--               (c) Jasper Van der Jeugt 2011
--
-- License     : BSD-style
-- Maintainer  : bos@serpentine.com
-- Stability   : experimental
-- Portability : GHC
--
-- /Warning/: this is an internal module, and does not have a stable
-- API or name. Functions in this module may not check or enforce
-- preconditions expected by public modules. Use at your own risk!
--
-- Core stream fusion functionality for text.

module Data.JSString.Internal.Fusion.Types
    (
      CC(..)
--    , M(..)
--    , M8
    , PairS(..)
    , RS(..)
    , Step(..)
    , Stream(..)
--    , Switch(..)
    , empty
    ) where

import Data.Text.Internal.Fusion.Types
-- import Data.Text.Internal.Fusion.Size
-- import Data.Word (Word8)

---- | Specialised tuple for case conversion.
--data CC s = CC !s {-# UNPACK #-} !Char {-# UNPACK #-} !Char
--
---- | Specialised, strict Maybe-like type.
--data M a = N
--         | J !a
--
--type M8 = M Word8
--
---- Restreaming state.
--data RS s
--    = RS0 !s
--    | RS1 !s {-# UNPACK #-} !Word8
--    | RS2 !s {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8
--    | RS3 !s {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8
--
--infixl 2 :*:
--data PairS a b = !a :*: !b
--                 -- deriving (Eq, Ord, Show)
--
---- | Allow a function over a stream to switch between two states.
--data Switch = S1 | S2
--
--data Step s a = Done
--              | Skip !s
--              | Yield !a !s
--
--{-
--instance (Show a) => Show (Step s a)
--    where show Done        = "Done"
--          show (Skip _)    = "Skip"
--          show (Yield x _) = "Yield " ++ show x
---}
--
--instance (Eq a) => Eq (Stream a) where
--    (==) = eq
--
--instance (Ord a) => Ord (Stream a) where
--    compare = cmp
--
---- The length hint in a Stream has two roles.  If its value is zero,
---- we trust it, and treat the stream as empty.  Otherwise, we treat it
---- as a hint: it should usually be accurate, so we use it when
---- unstreaming to decide what size array to allocate.  However, the
---- unstreaming functions must be able to cope with the hint being too
---- small or too large.
--
--data Stream a =
--    forall s. Stream
--    (s -> Step s a)             -- stepper function
--    !s                          -- current state
--
---- | /O(n)/ Determines if two streams are equal.
--eq :: (Eq a) => Stream a -> Stream a -> Bool
--eq (Stream next1 s1) (Stream next2 s2) = loop (next1 s1) (next2 s2)
--    where
--      loop Done Done                     = True
--      loop (Skip s1')     (Skip s2')     = loop (next1 s1') (next2 s2')
--      loop (Skip s1')     x2             = loop (next1 s1') x2
--      loop x1             (Skip s2')     = loop x1          (next2 s2')
--      loop Done _                        = False
--      loop _    Done                     = False
--      loop (Yield x1 s1') (Yield x2 s2') = x1 == x2 &&
--                                           loop (next1 s1') (next2 s2')
--{-# INLINE [0] eq #-}
--
--cmp :: (Ord a) => Stream a -> Stream a -> Ordering
--cmp (Stream next1 s1) (Stream next2 s2) = loop (next1 s1) (next2 s2)
--    where
--      loop Done Done                     = EQ
--      loop (Skip s1')     (Skip s2')     = loop (next1 s1') (next2 s2')
--      loop (Skip s1')     x2             = loop (next1 s1') x2
--      loop x1             (Skip s2')     = loop x1          (next2 s2')
--      loop Done _                        = LT
--      loop _    Done                     = GT
--      loop (Yield x1 s1') (Yield x2 s2') =
--          case compare x1 x2 of
--            EQ    -> loop (next1 s1') (next2 s2')
--            other -> other
--{-# INLINE [0] cmp #-}
--
---- | The empty stream.
--empty :: Stream a
--empty = Stream next ()
--    where next _ = Done
--{-# INLINE [0] empty #-}