content: {-# LANGUAGE BangPatterns #-}
  {-# LANGUAGE LambdaCase #-}
  {-# LANGUAGE MagicHash #-}
  {-# LANGUAGE RankNTypes #-}
  {-# LANGUAGE UnboxedTuples #-}
  {-# LANGUAGE UnboxedSums #-}
  
  {-# OPTIONS_GHC -O2 #-}
  
  module Packed.Bytes.Stream.ST
    ( ByteStream(..)
    , empty
    , unpack
    , fromBytes
    ) where
  
  import Data.Primitive (Array,ByteArray(..))
  import Data.Semigroup (Semigroup)
  import Data.Word (Word8)
  import GHC.Exts (RealWorld,State#,Int#,ByteArray#)
  import GHC.Int (Int(I#))
  import GHC.ST (ST(..))
  import Packed.Bytes (Bytes(..))
  import System.IO (Handle)
  import qualified Data.Primitive as PM
  import qualified Data.Semigroup as SG
  import qualified Packed.Bytes as B
  
  type Bytes# = (# ByteArray#, Int#, Int# #)
  
  newtype ByteStream s = ByteStream
    (State# s -> (# State# s, (# (# #) | (# Bytes# , ByteStream s #) #) #) )
  
  fromBytes :: Bytes -> ByteStream s
  fromBytes b = ByteStream
    (\s0 -> (# s0, (# | (# unboxBytes b, empty #) #) #))
  
  nextChunk :: ByteStream s -> ST s (Maybe (Bytes,ByteStream s))
  nextChunk (ByteStream f) = ST $ \s0 -> case f s0 of
    (# s1, r #) -> case r of
      (# (# #) | #) -> (# s1, Nothing #)
      (# | (# theBytes, theStream #) #) -> (# s1, Just (boxBytes theBytes, theStream) #)
  
  empty :: ByteStream s
  empty = ByteStream (\s -> (# s, (# (# #) | #) #) )
  
  boxBytes :: Bytes# -> Bytes
  boxBytes (# a, b, c #) = Bytes (ByteArray a) (I# b) (I# c)
  
  unboxBytes :: Bytes -> Bytes#
  unboxBytes (Bytes (ByteArray a) (I# b) (I# c)) = (# a,b,c #)
  
  unpack :: ByteStream s -> ST s [Word8]
  unpack stream = ST (unpackInternal stream)
  
  unpackInternal :: ByteStream s -> State# s -> (# State# s, [Word8] #)
  unpackInternal (ByteStream f) s0 = case f s0 of
    (# s1, r #) -> case r of
      (# (# #) | #) -> (# s1, [] #)
      (# | (# bytes, stream #) #) -> case unpackInternal stream s1 of
        (# s2, ws #) -> (# s2, B.unpack (boxBytes bytes) ++ ws #)
  
  