{-# LANGUAGE CPP           #-}
{-# LANGUAGE MagicHash     #-}
{-# LANGUAGE UnboxedTuples #-}
module Data.Text.Unsafe
    (
      inlineInterleaveST
    , inlinePerformIO
    , unsafeDupablePerformIO
    , Iter(..)
    , iter
    , iter_
    , reverseIter
    , reverseIter_
    , unsafeHead
    , unsafeTail
    , lengthWord8
    , takeWord8
    , dropWord8
    ) where
#if defined(ASSERTS)
import           Control.Exception                (assert)
#endif
import qualified Data.Text.Array                  as A
import           Data.Text.Internal               (Text (..))
import           Data.Text.Internal.Encoding.Utf8 (decodeCharIndex,
                                                   reverseDecodeCharIndex)
import           Data.Text.Internal.Unsafe        (inlineInterleaveST,
                                                   inlinePerformIO)
import           GHC.IO                           (unsafeDupablePerformIO)
unsafeHead :: Text -> Char
unsafeHead (Text arr off _len) =
  decodeCharIndex (\c _ -> c) (A.unsafeIndex arr) off
{-# INLINE unsafeHead #-}
unsafeTail :: Text -> Text
unsafeTail t@(Text arr off len) =
#if defined(ASSERTS)
    assert (d <= len) $
#endif
    Text arr (off+d) (len-d)
  where d = iter_ t 0
{-# INLINE unsafeTail #-}
data Iter = Iter {-# UNPACK #-} !Char {-# UNPACK #-} !Int
iter :: Text -> Int -> Iter
iter (Text arr off _len) i =
  decodeCharIndex (\c d -> Iter c d) (A.unsafeIndex arr) (off + i)
{-# INLINE iter #-}
iter_ :: Text -> Int -> Int
iter_ (Text arr off _len) i =
  decodeCharIndex (\_ n -> n) (\x -> A.unsafeIndex arr (x + off)) i
{-# INLINE iter_ #-}
reverseIter :: Text -> Int -> (Char,Int)
reverseIter (Text arr off _len) i =
    reverseDecodeCharIndex (\c s -> (c, -s)) idx (off + i)
  where
    idx = A.unsafeIndex arr
{-# INLINE reverseIter #-}
reverseIter_ :: Text -> Int -> Int
reverseIter_ (Text arr off _len) i =
  reverseDecodeCharIndex (\_ n -> -n) (\x -> A.unsafeIndex arr (x + off)) i
{-# INLINE reverseIter_ #-}
lengthWord8 :: Text -> Int
lengthWord8 (Text _arr _off len) = len
{-# INLINE lengthWord8 #-}
takeWord8 :: Int -> Text -> Text
takeWord8 k (Text arr off _len) = Text arr off k
{-# INLINE takeWord8 #-}
dropWord8 :: Int -> Text -> Text
dropWord8 k (Text arr off len) = Text arr (off+k) (len-k)
{-# INLINE dropWord8 #-}