{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP          #-}
{-# LANGUAGE MultiWayIf   #-}

module Data.Aeson.Internal.UnescapeFromText
  ( unescapeFromText
  ) where

import           Control.Exception           (throwIO, try)
import           Data.Bits                   (shiftL, shiftR, (.&.), (.|.))
import           Data.Text.Encoding.Error    (UnicodeException (..))
import           Data.Text.Internal          (Text (..))
import           Data.Text.Unsafe            (unsafeDupablePerformIO)

import           Data.Aeson.Internal.Prelude

import qualified Data.Primitive              as P
import qualified Data.Text.Array             as A
import qualified Data.Text.Internal          as T

#if !MIN_VERSION_text(2,0,0)
import           Data.Word                   (Word16)
#endif

-- | Unescape JSON text literal.
--
-- This function is exporeted mostly for testing and benchmarking purposes.
unescapeFromText :: Text -> Either UnicodeException Text
unescapeFromText :: Text -> Either UnicodeException Text
unescapeFromText = IO (Either UnicodeException Text) -> Either UnicodeException Text
forall a. IO a -> a
unsafeDupablePerformIO (IO (Either UnicodeException Text) -> Either UnicodeException Text)
-> (Text -> IO (Either UnicodeException Text))
-> Text
-> Either UnicodeException Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO Text -> IO (Either UnicodeException Text)
forall e a. Exception e => IO a -> IO (Either e a)
try (IO Text -> IO (Either UnicodeException Text))
-> (Text -> IO Text) -> Text -> IO (Either UnicodeException Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> IO Text
unescapeFromTextIO

throwDecodeError :: IO a
throwDecodeError :: forall a. IO a
throwDecodeError =
  let desc :: String
desc = String
"Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream"
   in UnicodeException -> IO a
forall e a. Exception e => e -> IO a
throwIO (String -> Maybe Word8 -> UnicodeException
DecodeError String
desc Maybe Word8
forall a. Maybe a
Nothing)

-------------------------------------------------------------------------------
-- unescapeTextIO
-------------------------------------------------------------------------------

type Offset = Int

unescapeFromTextIO :: Text -> IO Text

#if MIN_VERSION_text(2,0,0)

unescapeFromTextIO :: Text -> IO Text
unescapeFromTextIO (Text Array
src Offset
begin Offset
len) = do
    let end :: Offset
        end :: Offset
end = Offset
begin Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
len

    MutablePrimArray RealWorld Word8
arr <- Offset -> IO (MutablePrimArray (PrimState IO) Word8)
forall (m :: * -> *) a.
(PrimMonad m, Prim a) =>
Offset -> m (MutablePrimArray (PrimState m) a)
P.newPrimArray Offset
len

    let write3bytes :: Int -> Word8 -> Word8 -> Word8 -> Offset -> IO Text
        write3bytes :: Offset -> Word8 -> Word8 -> Word8 -> Offset -> IO Text
write3bytes !Offset
out !Word8
b1 !Word8
b2 !Word8
b3 !Offset
inp = do
          MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
b1
          Offset -> Word8 -> Word8 -> Offset -> IO Text
write2bytes (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word8
b2 Word8
b3 Offset
inp

        write2bytes :: Int -> Word8 -> Word8 -> Offset -> IO Text
        write2bytes :: Offset -> Word8 -> Word8 -> Offset -> IO Text
write2bytes !Offset
out !Word8
b1 !Word8
b2 !Offset
inp = do
          MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
b1
          Offset -> Word8 -> Offset -> IO Text
write1byte (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word8
b2 Offset
inp

        write1byte :: Int -> Word8 -> Offset -> IO Text
        write1byte :: Offset -> Word8 -> Offset -> IO Text
write1byte !Offset
out !Word8
b1 !Offset
inp = do
          MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
b1
          Offset -> Offset -> IO Text
state_start (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Offset
inp

        writeCodePoint :: Int -> Offset -> Word32 -> IO Text
        writeCodePoint :: Offset -> Offset -> Word32 -> IO Text
writeCodePoint !Offset
out !Offset
inp !Word32
acc
          | Word32
acc Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word32
127 = do
            MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out (Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
acc :: Word8)
            Offset -> Offset -> IO Text
state_start (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

          | Word32
acc Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word32
2047 = do
            let b1 :: Word8
b1 = Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftR Word32
acc Offset
6 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word32
192) :: Word8
            let b2 :: Word8
b2 = Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word32
acc Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
63) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word32
128) :: Word8
            MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
b1
            Offset -> Word8 -> Offset -> IO Text
write1byte (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word8
b2 (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

          | Word32
acc Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word32
65535 = do
            let b1 :: Word8
b1 = Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftR Word32
acc Offset
12 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word32
224) :: Word8
            let b2 :: Word8
b2 = Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftR Word32
acc Offset
6 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
63) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|.  Word32
128) :: Word8
            let b3 :: Word8
b3 = Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word32
acc Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
63) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word32
128) :: Word8
            MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
b1
            Offset -> Word8 -> Word8 -> Offset -> IO Text
write2bytes (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word8
b2 Word8
b3 (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

          | Bool
otherwise = do
            let b1 :: Word8
b1 = Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftR Word32
acc Offset
18 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word32
240) :: Word8
            let b2 :: Word8
b2 = Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftR Word32
acc Offset
12 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
63) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word32
128) :: Word8
            let b3 :: Word8
b3 = Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftR Word32
acc Offset
6 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
63) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word32
128) :: Word8
            let b4 :: Word8
b4 = Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word32
acc Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
63) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word32
128) :: Word8
            MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
b1
            Offset -> Word8 -> Word8 -> Word8 -> Offset -> IO Text
write3bytes (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word8
b2 Word8
b3 Word8
b4 (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

        state_sudone :: Int -> Offset -> Word32 -> Word32 -> IO Text
        state_sudone :: Offset -> Offset -> Word32 -> Word32 -> IO Text
state_sudone !Offset
out !Offset
inp !Word32
hi !Word32
lo
          | Word32
56320 Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word32
lo, Word32
lo Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word32
57343
          = Offset -> Offset -> Word32 -> IO Text
writeCodePoint Offset
out Offset
inp (Word32
65536 Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL (Word32
hi Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- Word32
55296) Offset
10 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|.  (Word32
lo Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- Word32
56320)))

          | Bool
otherwise
          = IO Text
forall a. IO a
throwDecodeError

        state_su4 :: Int -> Offset -> Word32 -> Word32 -> IO Text
        state_su4 :: Offset -> Offset -> Word32 -> Word32 -> IO Text
state_su4 !Offset
out !Offset
inp !Word32
hi !Word32
acc
          | Offset
inp Offset -> Offset -> Bool
forall a. Eq a => a -> a -> Bool
== Offset
end = IO Text
forall a. IO a
throwDecodeError
          | Bool
otherwise = do
            let !w8 :: Word8
w8 = Array -> Offset -> Word8
A.unsafeIndex Array
src Offset
inp
            if | Word8
48 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
57 ->
                 Offset -> Offset -> Word32 -> Word32 -> IO Text
state_sudone Offset
out Offset
inp Word32
hi (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
48))
               | Word8
65 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
70 ->
                 Offset -> Offset -> Word32 -> Word32 -> IO Text
state_sudone Offset
out Offset
inp Word32
hi (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
55))
               | Word8
97 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
102 ->
                 Offset -> Offset -> Word32 -> Word32 -> IO Text
state_sudone Offset
out Offset
inp Word32
hi (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
87))
               | Bool
otherwise ->
                 IO Text
forall a. IO a
throwDecodeError

        state_su3 :: Int -> Offset -> Word32 -> Word32 -> IO Text
        state_su3 :: Offset -> Offset -> Word32 -> Word32 -> IO Text
state_su3 !Offset
out !Offset
inp !Word32
hi !Word32
acc
          | Offset
inp Offset -> Offset -> Bool
forall a. Eq a => a -> a -> Bool
== Offset
end = IO Text
forall a. IO a
throwDecodeError
          | Bool
otherwise = do
            let !w8 :: Word8
w8 = Array -> Offset -> Word8
A.unsafeIndex Array
src Offset
inp
            if | Word8
48 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
57 ->
                 Offset -> Offset -> Word32 -> Word32 -> IO Text
state_su4 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word32
hi (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
48))
               | Word8
65 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
70 ->
                 Offset -> Offset -> Word32 -> Word32 -> IO Text
state_su4 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word32
hi (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
55))
               | Word8
97 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
102 ->
                 Offset -> Offset -> Word32 -> Word32 -> IO Text
state_su4 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word32
hi (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
87))
               | Bool
otherwise ->
                 IO Text
forall a. IO a
throwDecodeError

        state_su2 :: Int -> Offset -> Word32 -> Word32 -> IO Text
        state_su2 :: Offset -> Offset -> Word32 -> Word32 -> IO Text
state_su2 !Offset
out !Offset
inp !Word32
hi !Word32
acc
          | Offset
inp Offset -> Offset -> Bool
forall a. Eq a => a -> a -> Bool
== Offset
end = IO Text
forall a. IO a
throwDecodeError
          | Bool
otherwise = do
            let !w8 :: Word8
w8 = Array -> Offset -> Word8
A.unsafeIndex Array
src Offset
inp
            if | Word8
48 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
57 ->
                 Offset -> Offset -> Word32 -> Word32 -> IO Text
state_su3 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word32
hi (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
48))
               | Word8
65 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
70 ->
                 Offset -> Offset -> Word32 -> Word32 -> IO Text
state_su3 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word32
hi (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
55))
               | Word8
97 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
102 ->
                 Offset -> Offset -> Word32 -> Word32 -> IO Text
state_su3 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word32
hi (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
87))
               | Bool
otherwise ->
                 IO Text
forall a. IO a
throwDecodeError

        state_su1 :: Int -> Offset -> Word32 -> IO Text
        state_su1 :: Offset -> Offset -> Word32 -> IO Text
state_su1 !Offset
out !Offset
inp !Word32
hi
          | Offset
inp Offset -> Offset -> Bool
forall a. Eq a => a -> a -> Bool
== Offset
end = IO Text
forall a. IO a
throwDecodeError
          | Bool
otherwise = do
            let !w8 :: Word8
w8 = Array -> Offset -> Word8
A.unsafeIndex Array
src Offset
inp
            if | Word8
48 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
57 ->
                 Offset -> Offset -> Word32 -> Word32 -> IO Text
state_su2 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word32
hi (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
48))
               | Word8
65 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
70 ->
                 Offset -> Offset -> Word32 -> Word32 -> IO Text
state_su2 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word32
hi (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
55))
               | Word8
97 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
102 ->
                 Offset -> Offset -> Word32 -> Word32 -> IO Text
state_su2 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word32
hi (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
87))
               | Bool
otherwise ->
                 IO Text
forall a. IO a
throwDecodeError

        state_su :: Int -> Offset -> Word32 -> IO Text
        state_su :: Offset -> Offset -> Word32 -> IO Text
state_su !Offset
out !Offset
inp !Word32
hi
          | Offset
inp Offset -> Offset -> Bool
forall a. Eq a => a -> a -> Bool
== Offset
end = IO Text
forall a. IO a
throwDecodeError
          | Bool
otherwise = do
            let !w8 :: Word8
w8 = Array -> Offset -> Word8
A.unsafeIndex Array
src Offset
inp
            case Word8
w8 of
              Word8
117 -> Offset -> Offset -> Word32 -> IO Text
state_su1 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word32
hi
              Word8
_   -> IO Text
forall a. IO a
throwDecodeError

        state_ss :: Int -> Offset -> Word32 -> IO Text
        state_ss :: Offset -> Offset -> Word32 -> IO Text
state_ss !Offset
out !Offset
inp !Word32
hi
          | Offset
inp Offset -> Offset -> Bool
forall a. Eq a => a -> a -> Bool
== Offset
end = IO Text
forall a. IO a
throwDecodeError
          | Bool
otherwise = do
            let !w8 :: Word8
w8 = Array -> Offset -> Word8
A.unsafeIndex Array
src Offset
inp
            case Word8
w8 of
              Word8
92 -> Offset -> Offset -> Word32 -> IO Text
state_su Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word32
hi
              Word8
_  -> IO Text
forall a. IO a
throwDecodeError

        state_udone :: Int -> Offset -> Word32 -> IO Text
        state_udone :: Offset -> Offset -> Word32 -> IO Text
state_udone !Offset
out !Offset
inp !Word32
acc
          | Word32
acc Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
< Word32
55296 Bool -> Bool -> Bool
|| Word32
acc Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
> Word32
57343 =
            Offset -> Offset -> Word32 -> IO Text
writeCodePoint Offset
out Offset
inp Word32
acc

          | Word32
acc Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
< Word32
56320 =
            Offset -> Offset -> Word32 -> IO Text
state_ss Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) Word32
acc

          | Bool
otherwise =
            IO Text
forall a. IO a
throwDecodeError

        state_u4 :: Int -> Offset -> Word32 -> IO Text
        state_u4 :: Offset -> Offset -> Word32 -> IO Text
state_u4 !Offset
out !Offset
inp !Word32
acc
          | Offset
inp Offset -> Offset -> Bool
forall a. Eq a => a -> a -> Bool
== Offset
end = IO Text
forall a. IO a
throwDecodeError
          | Bool
otherwise = do
            let !w8 :: Word8
w8 = Array -> Offset -> Word8
A.unsafeIndex Array
src Offset
inp
            if | Word8
48 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
57 ->
                 Offset -> Offset -> Word32 -> IO Text
state_udone Offset
out Offset
inp (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
48))
               | Word8
65 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
70 ->
                 Offset -> Offset -> Word32 -> IO Text
state_udone Offset
out Offset
inp (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
55))
               | Word8
97 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
102 ->
                 Offset -> Offset -> Word32 -> IO Text
state_udone Offset
out Offset
inp (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
87))
               | Bool
otherwise ->
                 IO Text
forall a. IO a
throwDecodeError

        state_u3 :: Int -> Offset -> Word32 -> IO Text
        state_u3 :: Offset -> Offset -> Word32 -> IO Text
state_u3 !Offset
out !Offset
inp !Word32
acc
          | Offset
inp Offset -> Offset -> Bool
forall a. Eq a => a -> a -> Bool
== Offset
end = IO Text
forall a. IO a
throwDecodeError
          | Bool
otherwise = do
            let !w8 :: Word8
w8 = Array -> Offset -> Word8
A.unsafeIndex Array
src Offset
inp
            if | Word8
48 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
57 ->
                 Offset -> Offset -> Word32 -> IO Text
state_u4 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
48))
               | Word8
65 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
70 ->
                 Offset -> Offset -> Word32 -> IO Text
state_u4 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
55))
               | Word8
97 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
102 ->
                 Offset -> Offset -> Word32 -> IO Text
state_u4 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
87))
               | Bool
otherwise ->
                 IO Text
forall a. IO a
throwDecodeError

        state_u2 :: Int -> Offset -> Word32 -> IO Text
        state_u2 :: Offset -> Offset -> Word32 -> IO Text
state_u2 !Offset
out !Offset
inp !Word32
acc
          | Offset
inp Offset -> Offset -> Bool
forall a. Eq a => a -> a -> Bool
== Offset
end = IO Text
forall a. IO a
throwDecodeError
          | Bool
otherwise = do
            let !w8 :: Word8
w8 = Array -> Offset -> Word8
A.unsafeIndex Array
src Offset
inp
            if | Word8
48 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
57 ->
                 Offset -> Offset -> Word32 -> IO Text
state_u3 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
48))
               | Word8
65 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
70 ->
                 Offset -> Offset -> Word32 -> IO Text
state_u3 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
55))
               | Word8
97 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
102 ->
                 Offset -> Offset -> Word32 -> IO Text
state_u3 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Word32 -> Offset -> Word32
forall a. Bits a => a -> Offset -> a
shiftL Word32
acc Offset
4 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
87))
               | Bool
otherwise ->
                 IO Text
forall a. IO a
throwDecodeError

        state_u1 :: Int -> Offset -> IO Text
        state_u1 :: Offset -> Offset -> IO Text
state_u1 !Offset
out !Offset
inp
          | Offset
inp Offset -> Offset -> Bool
forall a. Eq a => a -> a -> Bool
== Offset
end = IO Text
forall a. IO a
throwDecodeError
          | Bool
otherwise = do
            let !w8 :: Word8
w8 = Array -> Offset -> Word8
A.unsafeIndex Array
src Offset
inp
            if | Word8
48 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
57 ->
                 Offset -> Offset -> Word32 -> IO Text
state_u2 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
48))
               | Word8
65 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
70 ->
                 Offset -> Offset -> Word32 -> IO Text
state_u2 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
55))
               | Word8
97 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
w8, Word8
w8 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
102 ->
                 Offset -> Offset -> Word32 -> IO Text
state_u2 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
w8 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
87))
               | Bool
otherwise ->
                 IO Text
forall a. IO a
throwDecodeError

        state_escape :: Int -> Offset -> IO Text
        state_escape :: Offset -> Offset -> IO Text
state_escape !Offset
out !Offset
inp
          | Offset
inp Offset -> Offset -> Bool
forall a. Eq a => a -> a -> Bool
== Offset
end = IO Text
forall a. IO a
throwDecodeError
          | Bool
otherwise  = do
            let !w8 :: Word8
w8 = Array -> Offset -> Word8
A.unsafeIndex Array
src Offset
inp
            case Word8
w8 of
              Word8
34 -> do
                MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
34
                Offset -> Offset -> IO Text
state_start (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

              Word8
92 -> do
                MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
92
                Offset -> Offset -> IO Text
state_start (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

              Word8
47 -> do
                MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
47
                Offset -> Offset -> IO Text
state_start (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

              Word8
98 -> do
                MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
8
                Offset -> Offset -> IO Text
state_start (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

              Word8
102 -> do
                MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
12
                Offset -> Offset -> IO Text
state_start (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

              Word8
110 -> do
                MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
10
                Offset -> Offset -> IO Text
state_start (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

              Word8
114 -> do
                MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
13
                Offset -> Offset -> IO Text
state_start (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

              Word8
116 -> do
                MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
9
                Offset -> Offset -> IO Text
state_start (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

              Word8
117 ->
                Offset -> Offset -> IO Text
state_u1 Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

              Word8
_ -> IO Text
forall a. IO a
throwDecodeError

        state_start :: Int -> Offset -> IO Text
        state_start :: Offset -> Offset -> IO Text
state_start !Offset
out !Offset
inp
          | Offset
inp Offset -> Offset -> Bool
forall a. Eq a => a -> a -> Bool
== Offset
end = do
            MutablePrimArray (PrimState IO) Word8 -> Offset -> IO ()
forall (m :: * -> *) a.
(PrimMonad m, Prim a) =>
MutablePrimArray (PrimState m) a -> Offset -> m ()
P.shrinkMutablePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out
            PrimArray Word8
frozenArr <- MutablePrimArray (PrimState IO) Word8 -> IO (PrimArray Word8)
forall (m :: * -> *) a.
PrimMonad m =>
MutablePrimArray (PrimState m) a -> m (PrimArray a)
P.unsafeFreezePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr
            Text -> IO Text
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> IO Text) -> Text -> IO Text
forall a b. (a -> b) -> a -> b
$ case PrimArray Word8
frozenArr of
              P.PrimArray ByteArray#
ba -> Array -> Offset -> Offset -> Text
T.Text (ByteArray# -> Array
A.ByteArray ByteArray#
ba) Offset
0 Offset
out

          | Bool
otherwise = do
            let !w8 :: Word8
w8 = Array -> Offset -> Word8
A.unsafeIndex Array
src Offset
inp
            if | Word8
w8 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
92  -> Offset -> Offset -> IO Text
state_escape Offset
out (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)
            -- because we are deserialising __valid__ text,
            -- we can simply copy everything else.
               | Bool
otherwise -> do
                 MutablePrimArray (PrimState IO) Word8 -> Offset -> Word8 -> IO ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Offset -> a -> m ()
P.writePrimArray MutablePrimArray RealWorld Word8
MutablePrimArray (PrimState IO) Word8
arr Offset
out Word8
w8
                 Offset -> Offset -> IO Text
state_start (Offset
out Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1) (Offset
inp Offset -> Offset -> Offset
forall a. Num a => a -> a -> a
+ Offset
1)

    -- start the state machine
    Offset -> Offset -> IO Text
state_start (Offset
0 :: Int) Offset
begin
#else

unescapeFromTextIO (Text src begin len) = do
    let end :: Offset
        end = begin + len

    arr <- P.newPrimArray len

    let state_sudone :: Int -> Offset -> Word32 -> IO Text
        state_sudone !out !inp !lo
          | 56320 <= lo, lo <= 57343 = do
            P.writePrimArray arr out (fromIntegral lo)
            state_start (out + 1) (inp + 1)

          | otherwise =
            throwDecodeError

        state_su4 :: Int -> Offset -> Word32 -> IO Text
        state_su4 !out !inp !acc
          | inp == end = throwDecodeError
          | otherwise = do
            let !w8 = A.unsafeIndex src inp
            if | 48 <= w8, w8 <= 57 ->
                 state_sudone out inp (shiftL acc 4 .|. fromIntegral (w8 - 48))
               | 65 <= w8, w8 <= 70 ->
                 state_sudone out inp (shiftL acc 4 .|. fromIntegral (w8 - 55))
               | 97 <= w8, w8 <= 102 ->
                 state_sudone out inp (shiftL acc 4 .|. fromIntegral (w8 - 87))
               | otherwise ->
                 throwDecodeError

        state_su3 :: Int -> Offset -> Word32 -> IO Text
        state_su3 !out !inp  !acc
          | inp == end = throwDecodeError
          | otherwise = do
            let !w8 = A.unsafeIndex src inp
            if | 48 <= w8, w8 <= 57 ->
                 state_su4 out (inp + 1) (shiftL acc 4 .|. fromIntegral (w8 - 48))
               | 65 <= w8, w8 <= 70 ->
                 state_su4 out (inp + 1) (shiftL acc 4 .|. fromIntegral (w8 - 55))
               | 97 <= w8, w8 <= 102 ->
                 state_su4 out (inp + 1) (shiftL acc 4 .|. fromIntegral (w8 - 87))
               | otherwise -> throwDecodeError

        state_su2 :: Int -> Offset -> Word32 -> IO Text
        state_su2 !out !inp !acc
          | inp == end = throwDecodeError
          | otherwise = do
            let !w8 = A.unsafeIndex src inp
            if | 48 <= w8, w8 <= 57 ->
                 state_su3 out (inp + 1) (shiftL acc 4 .|. fromIntegral (w8 - 48))
               | 65 <= w8, w8 <= 70 ->
                 state_su3 out (inp + 1) (shiftL acc 4 .|. fromIntegral (w8 - 55))
               | 97 <= w8, w8 <= 102 ->
                 state_su3 out (inp + 1) (shiftL acc 4 .|. fromIntegral (w8 - 87))
               | otherwise ->
                 throwDecodeError

        state_su1 :: Int -> Offset -> IO Text
        state_su1 !out !inp
          | inp == end = throwDecodeError
          | otherwise = do
            let !w8 = A.unsafeIndex src inp
            if | 48 <= w8, w8 <= 57 ->
                 state_su2 out (inp + 1) (fromIntegral (w8 - 48))
               | 65 <= w8, w8 <= 70 ->
                 state_su2 out (inp + 1) (fromIntegral (w8 - 55))
               | 97 <= w8, w8 <= 102 ->
                 state_su2 out (inp + 1) (fromIntegral (w8 - 87))
               | otherwise ->
                 throwDecodeError

        -- high surrogate u
        state_su :: Int -> Offset -> IO Text
        state_su !out !inp
          | inp == end = throwDecodeError
          | otherwise = do
            let !w8 = A.unsafeIndex src inp
            case w8 of
              117 -> state_su1 out (inp + 1)
              _   -> throwDecodeError

        -- high surrogate slash
        state_ss :: Int -> Offset -> IO Text
        state_ss !out !inp
          | inp == end = throwDecodeError
          | otherwise = do
            let !w8 = A.unsafeIndex src inp
            case w8 of
              92 -> state_su out (inp + 1)
              _  -> throwDecodeError

        state_udone :: Int -> Offset -> Word32 -> IO Text
        state_udone !out !inp !acc
          -- we know that codepoint in acc is in BMP
          | acc < 55296 || acc > 57343 = do
            P.writePrimArray arr out (fromIntegral acc)
            state_start (out + 1) (inp + 1)

          -- hi surrogate,
          -- we write it immediately (UTF16 as an output!)
          | acc < 56320 = do
            P.writePrimArray arr out (fromIntegral acc)
            state_ss (out + 1) (inp + 1)

          | otherwise =
            throwDecodeError

        state_u4 :: Int -> Offset -> Word32 -> IO Text
        state_u4 !out !inp !acc
          | inp == end = throwDecodeError
          | otherwise = do
            let !w8 = A.unsafeIndex src inp
            if | 48 <= w8, w8 <= 57 ->
                 state_udone out inp (shiftL acc 4 .|. fromIntegral (w8 - 48))
               | 65 <= w8, w8 <= 70 ->
                 state_udone out inp (shiftL acc 4 .|. fromIntegral (w8 - 55))
               | 97 <= w8, w8 <= 102 ->
                 state_udone out inp (shiftL acc 4 .|. fromIntegral (w8 - 87))
               | otherwise ->
                 throwDecodeError

        state_u3 :: Int -> Offset -> Word32 -> IO Text
        state_u3 !out !inp !acc
          | inp == end = throwDecodeError
          | otherwise = do
            let !w8 = A.unsafeIndex src inp
            if | 48 <= w8, w8 <= 57 ->
                 state_u4 out (inp + 1) (shiftL acc 4 .|. fromIntegral (w8 - 48))
               | 65 <= w8, w8 <= 70 ->
                 state_u4 out (inp + 1) (shiftL acc 4 .|. fromIntegral (w8 - 55))
               | 97 <= w8, w8 <= 102 ->
                 state_u4 out (inp + 1) (shiftL acc 4 .|. fromIntegral (w8 - 87))
               | otherwise ->
                 throwDecodeError

        state_u2 :: Int -> Offset -> Word32 -> IO Text
        state_u2 !out !inp !acc
          | inp == end = throwDecodeError
          | otherwise = do
            let !w8 = A.unsafeIndex src inp
            if | 48 <= w8, w8 <= 57 ->
                 state_u3 out (inp + 1) (shiftL acc 4 .|. fromIntegral (w8 - 48))
               | 65 <= w8, w8 <= 70 ->
                 state_u3 out (inp + 1) (shiftL acc 4 .|. fromIntegral (w8 - 55))
               | 97 <= w8, w8 <= 102 ->
                 state_u3 out (inp + 1) (shiftL acc 4 .|. fromIntegral (w8 - 87))
               | otherwise ->
                 throwDecodeError

        state_u1 :: Int -> Offset -> IO Text
        state_u1 !out !inp
          | inp == end = throwDecodeError
          | otherwise = do
            let !w8 = A.unsafeIndex src inp
            if | 48 <= w8, w8 <= 57 ->
                 state_u2 out (inp + 1) (fromIntegral (w8 - 48))
               | 65 <= w8, w8 <= 70 ->
                 state_u2 out (inp + 1) (fromIntegral (w8 - 55))
               | 97 <= w8, w8 <= 102 ->
                 state_u2 out (inp + 1) (fromIntegral (w8 - 87))
               | otherwise ->
                 throwDecodeError

        state_escape :: Int -> Offset -> IO Text
        state_escape out inp
          | inp == end = throwDecodeError
          | otherwise = do
            let !w8 = A.unsafeIndex src inp
            case w8 of
              34 -> do
                P.writePrimArray arr out 34
                state_start (out + 1) (inp + 1)

              92 -> do
                P.writePrimArray arr out 92
                state_start (out + 1) (inp + 1)

              47 -> do
                P.writePrimArray arr out 47
                state_start (out + 1) (inp + 1)

              98 -> do
                P.writePrimArray arr out 8
                state_start (out + 1) (inp + 1)

              102 -> do
                P.writePrimArray arr out 12
                state_start (out + 1) (inp + 1)

              110 -> do
                P.writePrimArray arr out 10
                state_start (out + 1) (inp + 1)

              114 -> do
                P.writePrimArray arr out 13
                state_start (out + 1) (inp + 1)

              116 -> do
                P.writePrimArray arr out 9
                state_start (out + 1) (inp + 1)

              117 ->
                state_u1 out (inp + 1)

              _ -> throwDecodeError

        state_start :: Int -> Offset -> IO Text
        state_start !out !inp
          | inp == end = do
            P.shrinkMutablePrimArray arr out
            frozenArr <- P.unsafeFreezePrimArray arr
            return $ case frozenArr of
              P.PrimArray ba -> T.Text (A.Array ba) 0 out

          | otherwise = do
            let !w8 = A.unsafeIndex src inp
            if | w8 == 92 -> state_escape out (inp + 1)
            -- because we are deserialising __valid__ text,
            -- we can simply copy everything else.
               | otherwise -> do
                  P.writePrimArray arr out (fromIntegral w8 :: Word16)
                  state_start (out + 1) (inp + 1)

    -- start the state machine
    state_start (0 :: Int) begin

#endif