{-# OPTIONS_GHC -O2 #-}
-- -O2: its loops over every byte sent run 15 to 20% faster than at -O1
-- (Bench.Encode "large params"); library-wide -O2 made row parsing slower.
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
-- | Encoding 'Text' as UTF-16LE, as every string the client sends is: the
-- SQL text of a batch or @sp_executesql@, @nvarchar@ parameters, parameter
-- names, LOGIN7's strings; and decoding UTF-16LE into 'Text', as every
-- string the server sends is.
--
-- The encoder is a transcoder straight from the UTF-8 array of a 'Text'.
-- @text@'s own 'Data.Text.Encoding.encodeUtf16LE' (text 2.1) goes through
-- stream fusion into a buffer that doubles as it grows: about 14 ns and
-- 100 bytes of allocation per character.  Here ASCII runs take eight bytes
-- per step, and the output is written once into a buffer of its exact
-- size.  The decoder likewise writes UTF-8 straight into a 'Text' array.
module Hmssql.Tds.Utf16
  ( encodeUtf16LE
  , utf16Length
  , unsafeWriteUtf16LE
  , utf16LEBuilder
  , decodeUtf16LE
  , decodeUtf16Chunks
  ) where

import Streaming (Stream, Of)
import qualified Streaming as S
import qualified Streaming.Prelude as S
import Control.Monad.ST (RealWorld, stToIO)
import Data.Array.Byte (MutableByteArray (..))
import Data.Bits (shiftL, shiftR, unsafeShiftL, unsafeShiftR, (.&.), (.|.))
import qualified Data.ByteString as B
import qualified Data.ByteString.Builder as BB
import qualified Data.ByteString.Builder.Internal as BBI
import qualified Data.ByteString.Internal as BI
import qualified Data.Text as T
import Data.Text.Internal (Text (..))
import qualified Data.Text.Array as A
import Data.Word (Word16, Word32, Word64, Word8)
import Foreign.ForeignPtr (withForeignPtr)
import Foreign.Ptr (Ptr, minusPtr, plusPtr)
import Foreign.Storable (peekByteOff, pokeByteOff)
import GHC.ByteOrder (ByteOrder (..), targetByteOrder)
import GHC.Exts (Int (..), indexWord8ArrayAsWord64#, writeWord8ArrayAsWord32#, writeWord8ArrayAsWord64#)
import GHC.IO (IO (..))
import GHC.Word (Word32 (..), Word64 (..))
import System.IO.Unsafe (unsafeDupablePerformIO)

import Hmssql.Tds.Bytes.Unsafe (peekWord16LE, peekWord64LE, pokeWord64LE)

-- | The text in UTF-16LE, without a byte order mark.  The same bytes as
-- 'Data.Text.Encoding.encodeUtf16LE'.
encodeUtf16LE :: Text -> B.ByteString
encodeUtf16LE :: Text -> ByteString
encodeUtf16LE t :: Text
t@(Text Array
_ Int
_ Int
len)
  | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = ByteString
B.empty
  | Bool
otherwise = IO ByteString -> ByteString
forall a. IO a -> a
unsafeDupablePerformIO (IO ByteString -> ByteString) -> IO ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ do
      -- Each UTF-8 byte makes at most one UTF-16 code unit (a four-byte
      -- sequence makes two), so 2 * len bytes always suffice, and are
      -- exact for ASCII.
      fp <- Int -> IO (ForeignPtr Word8)
forall a. Int -> IO (ForeignPtr a)
BI.mallocByteString (Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
len)
      n <- withForeignPtr fp (unsafeWriteUtf16LE t)
      pure $! if n == 2 * len then BI.BS fp n else B.copy (BI.BS fp n)
{-# NOINLINE encodeUtf16LE #-}
-- Out of line: its 28 call sites each had a copy of the allocation and the size
-- check, 19 KB of the library's object code; the encoding benchmarks allocate the
-- same, and the call is small beside the conversion.

-- | 'encodeUtf16LE' as a 'BB.Builder', written straight into the builder's
-- buffer, a piece at a time for text too long for one of 32 KiB.
utf16LEBuilder :: Text -> BB.Builder
utf16LEBuilder :: Text -> Builder
utf16LEBuilder t :: Text
t@(Text Array
_ Int
_ Int
len)
  | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Builder
forall a. Monoid a => a
mempty
  | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
16376 = let (Text
here, Text
rest) = Int -> Text -> (Text, Text)
T.splitAt Int
2048 Text
t in Text -> Builder
utf16LEBuilder Text
here Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
utf16LEBuilder Text
rest
  | Bool
otherwise = (forall r. BuildStep r -> BuildStep r) -> Builder
BBI.builder BuildStep r -> BuildStep r
forall r. BuildStep r -> BuildStep r
step
  where
    step :: BBI.BuildStep r -> BBI.BuildStep r
    step :: forall r. BuildStep r -> BuildStep r
step BuildStep r
k (BBI.BufferRange Ptr Word8
op Ptr Word8
ope)
      | Ptr Word8
ope Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr` Ptr Word8
op Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
len = do
          n <- Text -> Ptr Word8 -> IO Int
unsafeWriteUtf16LE Text
t Ptr Word8
op
          k (BBI.BufferRange (op `plusPtr` n) ope)
      | Bool
otherwise = BuildSignal r -> IO (BuildSignal r)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> Ptr Word8 -> BuildStep r -> BuildSignal r
forall a. Int -> Ptr Word8 -> BuildStep a -> BuildSignal a
BBI.bufferFull (Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
len) Ptr Word8
op (BuildStep r -> BuildStep r
forall r. BuildStep r -> BuildStep r
step BuildStep r
k))

-- | The length of the text in UTF-16 code units: its characters, plus one
-- for each outside the Basic Multilingual Plane.  (Every UTF-8 byte that
-- isn't a continuation byte starts a character, and a four-byte sequence
-- is a surrogate pair.)
utf16Length :: Text -> Int
utf16Length :: Text -> Int
utf16Length (Text Array
arr Int
off Int
len) = Int -> Int -> Int
forall {t}. Num t => Int -> t -> t
go Int
off Int
0
  where
    end :: Int
end = Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len
    go :: Int -> t -> t
go !Int
i !t
n
      | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
end = t
n
      | Bool
otherwise =
          let b :: Word8
b = Array -> Int -> Word8
A.unsafeIndex Array
arr Int
i
           in Int -> t -> t
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (t
n t -> t -> t
forall a. Num a => a -> a -> a
+ (if Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0xC0 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
0x80 then t
1 else t
0) t -> t -> t
forall a. Num a => a -> a -> a
+ (if Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
0xF0 then t
1 else t
0))

-- | Write UTF-16LE into caller-owned memory without checking capacity.
-- Returns the byte count written: @2 * utf16Length text@, with no byte
-- order mark or terminator.
--
-- The pointer must remain valid and writable for at least that many bytes
-- throughout the call. Twice the text's UTF-8 byte length is a sufficient
-- upper bound when avoiding a length scan. Size and offset arithmetic must
-- fit in 'Int'; source and destination must not overlap, and the caller
-- must respect the lifetime and immutability of any aliases to the buffer.
-- Use 'encodeUtf16LE' or 'utf16LEBuilder' to let the library provide storage.
unsafeWriteUtf16LE :: Text -> Ptr Word8 -> IO Int
unsafeWriteUtf16LE :: Text -> Ptr Word8 -> IO Int
unsafeWriteUtf16LE (Text Array
arr Int
off Int
len) Ptr Word8
p = Int -> Int -> IO Int
go Int
off Int
0
  where
    end :: Int
end = Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len
    go :: Int -> Int -> IO Int
go !Int
i !Int
o
      | ByteOrder
targetByteOrder ByteOrder -> ByteOrder -> Bool
forall a. Eq a => a -> a -> Bool
== ByteOrder
LittleEndian, Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
8 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
end, Word64 -> Bool
forall {a}. (Bits a, Num a) => a -> Bool
ascii8 Word64
w = do
          -- Eight ASCII bytes: spread each to 16 bits.
          Ptr Word8 -> Int -> Word64 -> IO ()
pokeWord64LE Ptr Word8
p Int
o (Word64 -> Word64
spread Word64
w)
          Ptr Word8 -> Int -> Word64 -> IO ()
pokeWord64LE Ptr Word8
p (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
8) (Word64 -> Word64
spread (Word64
w Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
32))
          Int -> Int -> IO Int
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
8) (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
16)
      | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
end = Int -> IO Int
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
o
      | Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x80 = Int -> Word16 -> IO ()
unit Int
o (Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
b) IO () -> IO Int -> IO Int
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Int -> Int -> IO Int
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)
      | Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0xE0 = do
          Int -> Word16 -> IO ()
unit Int
o ((Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1F) Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
`shiftL` Int
6) Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.|. Int -> Word16
cont Int
1)
          Int -> Int -> IO Int
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)
      | Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0xF0 = do
          Int -> Word16 -> IO ()
unit Int
o ((Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x0F) Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
`shiftL` Int
12) Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.|. (Int -> Word16
cont Int
1 Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
`shiftL` Int
6) Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.|. Int -> Word16
cont Int
2)
          Int -> Int -> IO Int
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3) (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)
      | Bool
otherwise = do
          let c :: Int
c = ((Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
b Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x07) :: Int) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` Int
18)
                Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word16
cont Int
1) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` Int
12) Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word16
cont Int
2) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` Int
6)
                Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word16
cont Int
3)
              c' :: Int
c' = Int
c Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
0x10000
          Int -> Word16 -> IO ()
unit Int
o (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
0xD800 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int
c' Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftR` Int
10)))
          Int -> Word16 -> IO ()
unit (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
0xDC00 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int
c' Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x3FF)))
          Int -> Int -> IO Int
go (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4) (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4)
      where
        b :: Word8
b = Array -> Int -> Word8
A.unsafeIndex Array
arr Int
i
        w :: Word64
w = Int -> Word64
word64At (Int
i :: Int)
        cont :: Int -> Word16
        cont :: Int -> Word16
cont Int
k = Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Array -> Int -> Word8
A.unsafeIndex Array
arr (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
k) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x3F)
    unit :: Int -> Word16 -> IO ()
    unit :: Int -> Word16 -> IO ()
unit Int
o Word16
u = do
      Ptr Word8 -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Word8
p Int
o (Word16 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
u :: Word8)
      Ptr Word8 -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Word8
p (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Word16 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16
u Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
8) :: Word8)
    ascii8 :: a -> Bool
ascii8 a
x = a
x a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0x8080808080808080 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0
    -- The low four bytes of @x@, each widened to 16 bits (little-endian).
    spread :: Word64 -> Word64
    spread :: Word64 -> Word64
spread Word64
x0 =
      let x1 :: Word64
x1 = Word64
x0 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xFFFFFFFF
          x2 :: Word64
x2 = (Word64
x1 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
x1 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`unsafeShiftL` Int
16)) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0x0000FFFF0000FFFF
       in (Word64
x2 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
x2 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`unsafeShiftL` Int
8)) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0x00FF00FF00FF00FF
    word64At :: Int -> Word64
word64At (I# Int#
i) = case Array
arr of
      A.ByteArray ByteArray#
ba -> Word64# -> Word64
W64# (ByteArray# -> Int# -> Word64#
indexWord8ArrayAsWord64# ByteArray#
ba Int#
i)

------------------------------------------------------------------------------
-- Decoding

-- One pass, writing UTF-8 into a 'Text' array.  While the text is ASCII it
-- goes into an array of one byte per code unit, eight units per step; at
-- the first unit that isn't ASCII, the array grows to room for three bytes
-- per remaining unit (the most any unit takes: a surrogate pair is four
-- bytes for two units, U+FFFD three for one), and the rest is decoded unit
-- by unit, back to eight at a time after each ASCII unit.  The array is
-- then cut to its length (copied, if it is large and a good part of it is
-- unused, so that a kept value doesn't keep the slack).
--
-- The buffer's bytes are read in 'IO', with the buffer kept alive for the
-- whole decode ('withForeignPtr'); the decode is pure from outside
-- ('unsafeDupablePerformIO'). The private loop checks each read against the
-- value's length.

-- | Decode UTF-16LE text from the server, never failing: each ill-formed
-- code unit (an unpaired surrogate) becomes one U+FFFD, and so does a
-- trailing odd byte.  'Hmssql.Tds.Primitives.decodeUtf16LE' says why.
decodeUtf16LE :: B.ByteString -> Text
decodeUtf16LE :: ByteString -> Text
decodeUtf16LE (BI.BS ForeignPtr Word8
fp Int
len)
  | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = Text
T.empty
  | Bool
otherwise = IO Text -> Text
forall a. IO a -> a
unsafeDupablePerformIO (IO Text -> Text) -> IO Text -> Text
forall a b. (a -> b) -> a -> b
$ ForeignPtr Word8 -> (Ptr Word8 -> IO Text) -> IO Text
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
fp ((Ptr Word8 -> IO Text) -> IO Text)
-> (Ptr Word8 -> IO Text) -> IO Text
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> do
      let units :: Int
units = Int
len Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
1
      -- One byte per unit if the text starts with ASCII (it may all
      -- be), else the most it can take.
      startsAscii <-
        if Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2
          then (\Word8
b1 Word8
b0 -> Word8
b1 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== (Word8
0 :: Word8) Bool -> Bool -> Bool
&& Word8
b0 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< (Word8
0x80 :: Word8)) (Word8 -> Word8 -> Bool) -> IO Word8 -> IO (Word8 -> Bool)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr Word8 -> Int -> IO Word8
forall b. Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr Word8
p Int
1 IO (Word8 -> Bool) -> IO Word8 -> IO Bool
forall a b. IO (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Ptr Word8 -> Int -> IO Word8
forall b. Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr Word8
p Int
0
          else Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
      let cap0 = if Bool
startsAscii then Int
units else Int -> Int -> Int
maxLength Int
0 Int
len
      marr0 <- stToIO (A.new cap0)
      (marr, cap, n) <- decodeInto p len marr0 cap0
      arr <- stToIO $ if
        | n == cap -> A.unsafeFreeze marr
        | cap > 4096 && cap - n > cap `unsafeShiftR` 3 -> do
            exact <- A.new n
            A.copyM exact 0 marr 0 n
            A.unsafeFreeze exact
        | otherwise -> A.shrinkM marr n >> A.unsafeFreeze marr
      pure (Text arr 0 n)

-- | 'decodeUtf16LE' for a value that arrives in chunks: the result is the same
-- however the value is cut.  SQL Server ends PLP chunks at packet ends, which
-- can fall inside a code unit or a surrogate pair.  Only the pending character,
-- at most three bytes, is copied between chunks.
decodeUtf16Chunks :: Monad m => Stream (Of B.ByteString) m r -> Stream (Of T.Text) m r
decodeUtf16Chunks :: forall (m :: * -> *) r.
Monad m =>
Stream (Of ByteString) m r -> Stream (Of Text) m r
decodeUtf16Chunks = ByteString -> Stream (Of ByteString) m r -> Stream (Of Text) m r
forall {m :: * -> *} {r}.
Monad m =>
ByteString -> Stream (Of ByteString) m r -> Stream (Of Text) m r
go ByteString
B.empty
  where
    go :: ByteString -> Stream (Of ByteString) m r -> Stream (Of Text) m r
go ByteString
carry Stream (Of ByteString) m r
source = m (Stream (Of Text) m r) -> Stream (Of Text) m r
forall (m :: * -> *) (f :: * -> *) r.
(Monad m, Functor f) =>
m (Stream f m r) -> Stream f m r
S.effect (m (Stream (Of Text) m r) -> Stream (Of Text) m r)
-> m (Stream (Of Text) m r) -> Stream (Of Text) m r
forall a b. (a -> b) -> a -> b
$ Stream (Of ByteString) m r
-> m (Either r (ByteString, Stream (Of ByteString) m r))
forall (m :: * -> *) a r.
Monad m =>
Stream (Of a) m r -> m (Either r (a, Stream (Of a) m r))
S.next Stream (Of ByteString) m r
source m (Either r (ByteString, Stream (Of ByteString) m r))
-> (Either r (ByteString, Stream (Of ByteString) m r)
    -> m (Stream (Of Text) m r))
-> m (Stream (Of Text) m r)
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      Left r
r -> Stream (Of Text) m r -> m (Stream (Of Text) m r)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> Stream (Of Text) m ()
forall {m :: * -> *}. Monad m => Text -> Stream (Of Text) m ()
emit (ByteString -> Text
decodeUtf16LE ByteString
carry) Stream (Of Text) m ()
-> Stream (Of Text) m r -> Stream (Of Text) m r
forall a b.
Stream (Of Text) m a
-> Stream (Of Text) m b -> Stream (Of Text) m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> r -> Stream (Of Text) m r
forall a. a -> Stream (Of Text) m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure r
r)
      Right (ByteString
bs, Stream (Of ByteString) m r
next) ->
        let ([Text]
texts, ByteString
tailBytes) = ByteString -> ByteString -> ([Text], ByteString)
push ByteString
carry ByteString
bs
         in Stream (Of Text) m r -> m (Stream (Of Text) m r)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((Text -> Stream (Of Text) m ()) -> [Text] -> Stream (Of Text) m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Text -> Stream (Of Text) m ()
forall {m :: * -> *}. Monad m => Text -> Stream (Of Text) m ()
emit [Text]
texts Stream (Of Text) m ()
-> Stream (Of Text) m r -> Stream (Of Text) m r
forall a b.
Stream (Of Text) m a
-> Stream (Of Text) m b -> Stream (Of Text) m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ByteString -> Stream (Of ByteString) m r -> Stream (Of Text) m r
go ByteString
tailBytes Stream (Of ByteString) m r
next)
    emit :: Text -> Stream (Of Text) m ()
emit Text
t = if Text -> Bool
T.null Text
t then () -> Stream (Of Text) m ()
forall a. a -> Stream (Of Text) m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure () else Text -> Stream (Of Text) m ()
forall (m :: * -> *) a. Monad m => a -> Stream (Of a) m ()
S.yield Text
t
    -- Complete the carried character from the new chunk, then decode the rest of
    -- the chunk in place.  An unpaired surrogate decodes to U+FFFD as it would in
    -- a whole value, so it isn't held back once the next unit shows it is unpaired.
    push :: ByteString -> ByteString -> ([Text], ByteString)
push ByteString
carry ByteString
bs
      | ByteString -> Bool
B.null ByteString
carry = ByteString -> ([Text], ByteString)
block ByteString
bs
      | ByteString -> Bool
B.null ByteString
bs = ([], ByteString
carry)
      | ByteString -> Int
B.length ByteString
prefix Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
2 Bool -> Bool -> Bool
|| (Int -> Bool
forall {a}. (Ord a, Num a) => a -> Bool
high Int
first Bool -> Bool -> Bool
&& ByteString -> Int
B.length ByteString
prefix Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
4) = ([], ByteString -> ByteString
B.copy ByteString
prefix)
      | Bool
otherwise =
          let n :: Int
n = if Int -> Bool
forall {a}. (Ord a, Num a) => a -> Bool
high Int
first Bool -> Bool -> Bool
&& Int -> Bool
forall {a}. (Ord a, Num a) => a -> Bool
low (ByteString -> Int -> Int
unit ByteString
prefix Int
2) then Int
4 else Int
2
              text :: Text
text = ByteString -> Text
decodeUtf16LE (Int -> ByteString -> ByteString
B.take Int
n ByteString
prefix)
              ([Text]
later, ByteString
pending) = if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= ByteString -> Int
B.length ByteString
carry
                then ByteString -> ([Text], ByteString)
block (Int -> ByteString -> ByteString
B.drop (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
B.length ByteString
carry) ByteString
bs)
                else ByteString -> ByteString -> ([Text], ByteString)
push (Int -> ByteString -> ByteString
B.drop Int
n ByteString
carry) ByteString
bs
           in (Text
text Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text]
later, ByteString
pending)
      where
        prefix :: ByteString
prefix = ByteString
carry ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Int -> ByteString -> ByteString
B.take (Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
B.length ByteString
carry) ByteString
bs
        first :: Int
first = ByteString -> Int -> Int
unit ByteString
prefix Int
0
    -- All but a trailing odd byte or a high surrogate, which wait for their rest.
    block :: ByteString -> ([Text], ByteString)
block ByteString
bs =
      let evenLength :: Int
evenLength = ByteString -> Int
B.length ByteString
bs Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
B.length ByteString
bs Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
2
          n :: Int
n = if Int
evenLength Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2 Bool -> Bool -> Bool
&& Int -> Bool
forall {a}. (Ord a, Num a) => a -> Bool
high (ByteString -> Int -> Int
unit ByteString
bs (Int
evenLength Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2)) then Int
evenLength Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2 else Int
evenLength
       in ([ByteString -> Text
decodeUtf16LE (Int -> ByteString -> ByteString
B.take Int
n ByteString
bs)], ByteString -> ByteString
B.copy (Int -> ByteString -> ByteString
B.drop Int
n ByteString
bs))
    unit :: ByteString -> Int -> Int
unit ByteString
bs Int
i = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
B.index ByteString
bs Int
i) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
256 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
B.index ByteString
bs (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)) :: Int
    high :: a -> Bool
high a
n = a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0xD800 Bool -> Bool -> Bool
&& a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
0xDBFF
    low :: a -> Bool
low a
n = a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0xDC00 Bool -> Bool -> Bool
&& a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
0xDFFF

-- | Decode the @len@ bytes at the pointer into the array (of capacity
-- @cap0@, the number of whole code units), growing it once if the text
-- isn't all ASCII.  Returns the array, its capacity and the number of
-- bytes written.
decodeInto :: Ptr Word8 -> Int -> A.MArray RealWorld -> Int -> IO (A.MArray RealWorld, Int, Int)
decodeInto :: Ptr Word8
-> Int
-> MArray RealWorld
-> Int
-> IO (MArray RealWorld, Int, Int)
decodeInto Ptr Word8
p Int
len MArray RealWorld
marr0 Int
cap0 = Int -> Int -> IO (MArray RealWorld, Int, Int)
ascii Int
0 Int
0
  where
    -- The ASCII prefix, into the array of one byte per unit: eight units
    -- at a time while they last, then one.
    ascii :: Int -> Int -> IO (MArray RealWorld, Int, Int)
ascii !Int
i !Int
o
      | ByteOrder
targetByteOrder ByteOrder -> ByteOrder -> Bool
forall a. Eq a => a -> a -> Bool
== ByteOrder
LittleEndian, Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
16 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
len = do
          w0 <- Int -> IO Word64
word64At Int
i
          w1 <- word64At (i + 8)
          if asciiUnits (w0 .|. w1)
            then writeW64 marr0 o (narrow w0 .|. (narrow w1 `unsafeShiftL` 32)) >> ascii (i + 16) (o + 8)
            else asciiUnit i o
      | Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
len = Int -> Int -> IO (MArray RealWorld, Int, Int)
asciiUnit Int
i Int
o
      | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
len = (MArray RealWorld, Int, Int) -> IO (MArray RealWorld, Int, Int)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (MArray RealWorld
marr0, Int
cap0, Int
o)
      | Bool
otherwise = Int -> Int -> IO (MArray RealWorld, Int, Int)
grow Int
i Int
o  -- an odd trailing byte
    asciiUnit :: Int -> Int -> IO (MArray RealWorld, Int, Int)
asciiUnit !Int
i !Int
o = do
      u <- Int -> IO Int
unitAt Int
i
      if u < 0x80
        then writeW8 marr0 o (fromIntegral u) >> ascii (i + 2) (o + 1)
        else grow i o
    -- Not ASCII (or an odd trailing byte): room for the most the rest can
    -- take, and the general loop.
    grow :: Int -> Int -> IO (MArray RealWorld, Int, Int)
grow !Int
i !Int
o = do
      let cap :: Int
cap = Int -> Int -> Int
maxLength Int
o (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i)
      marr <- if Int
cap Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
cap0 then MArray RealWorld -> IO (MArray RealWorld)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure MArray RealWorld
marr0 else ST RealWorld (MArray RealWorld) -> IO (MArray RealWorld)
forall a. ST RealWorld a -> IO a
stToIO (MArray RealWorld -> Int -> ST RealWorld (MArray RealWorld)
forall s. MArray s -> Int -> ST s (MArray s)
A.resizeM MArray RealWorld
marr0 Int
cap)
      o' <- general marr i o
      pure (marr, max cap cap0, o')

    general :: A.MArray RealWorld -> Int -> Int -> IO Int
    general :: MArray RealWorld -> Int -> Int -> IO Int
general MArray RealWorld
marr = Int -> Int -> IO Int
go
      where
        go :: Int -> Int -> IO Int
go !Int
i !Int
o
          | Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
len =
              if Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
len then Int -> IO ()
replacement Int
o IO () -> IO Int -> IO Int
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Int -> IO Int
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3) else Int -> IO Int
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
o
          | Bool
otherwise = do
              u <- Int -> IO Int
unitAt Int
i
              if
                | u < 0x80 -> writeW8 marr o (fromIntegral u) >> run (i + 2) (o + 1)
                | u < 0x800 -> do
                    writeW8 marr o (fromIntegral (0xC0 .|. (u `unsafeShiftR` 6)))
                    writeW8 marr (o + 1) (fromIntegral (0x80 .|. (u .&. 0x3F)))
                    go (i + 2) (o + 2)
                | u < 0xD800 || u > 0xDFFF -> three u o >> go (i + 2) (o + 3)
                | u <= 0xDBFF, i + 4 <= len -> do
                    lo <- unitAt (i + 2)
                    if lo >= 0xDC00 && lo <= 0xDFFF
                      then do
                        let c = Int
0x10000 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ((Int
u Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
0xD800) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftL` Int
10) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int
lo Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
0xDC00)
                        writeW8 marr o (fromIntegral (0xF0 .|. (c `unsafeShiftR` 18)))
                        writeW8 marr (o + 1) (fromIntegral (0x80 .|. ((c `unsafeShiftR` 12) .&. 0x3F)))
                        writeW8 marr (o + 2) (fromIntegral (0x80 .|. ((c `unsafeShiftR` 6) .&. 0x3F)))
                        writeW8 marr (o + 3) (fromIntegral (0x80 .|. (c .&. 0x3F)))
                        go (i + 4) (o + 4)
                      else replacement o >> go (i + 2) (o + 3)
                | otherwise -> replacement o >> go (i + 2) (o + 3)
        -- After an ASCII unit: eight at a time while they last.
        run :: Int -> Int -> IO Int
run !Int
i !Int
o
          | ByteOrder
targetByteOrder ByteOrder -> ByteOrder -> Bool
forall a. Eq a => a -> a -> Bool
== ByteOrder
LittleEndian, Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
16 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
len = do
              w0 <- Int -> IO Word64
word64At Int
i
              w1 <- word64At (i + 8)
              if asciiUnits (w0 .|. w1)
                then writeW64 marr o (narrow w0 .|. (narrow w1 `unsafeShiftL` 32)) >> run (i + 16) (o + 8)
                else go i o
          | Bool
otherwise = Int -> Int -> IO Int
go Int
i Int
o
        -- One four-byte store (the array has a byte of slack for it).
        three :: Int -> Int -> IO ()
        three :: Int -> Int -> IO ()
three Int
c Int
o
          | ByteOrder
targetByteOrder ByteOrder -> ByteOrder -> Bool
forall a. Eq a => a -> a -> Bool
== ByteOrder
LittleEndian =
              MArray RealWorld -> Int -> Word32 -> IO ()
writeW32 MArray RealWorld
marr Int
o (Word32 -> IO ()) -> Word32 -> IO ()
forall a b. (a -> b) -> a -> b
$ Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word32) -> Int -> Word32
forall a b. (a -> b) -> a -> b
$
                (Int
0xE0 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
c Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
12))
                  Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. ((Int
0x80 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. ((Int
c Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
6) Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x3F)) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftL` Int
8)
                  Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. ((Int
0x80 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
c Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x3F)) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftL` Int
16)
          | Bool
otherwise = do
              MArray RealWorld -> Int -> Word8 -> IO ()
writeW8 MArray RealWorld
marr Int
o (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
0xE0 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
c Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
12)))
              MArray RealWorld -> Int -> Word8 -> IO ()
writeW8 MArray RealWorld
marr (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
0x80 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. ((Int
c Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
6) Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x3F)))
              MArray RealWorld -> Int -> Word8 -> IO ()
writeW8 MArray RealWorld
marr (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
0x80 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
c Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x3F)))
        replacement :: Int -> IO ()
replacement = Int -> Int -> IO ()
three Int
0xFFFD

    -- The code unit at a byte offset (the caller has checked that it is
    -- within the span).
    unitAt :: Int -> IO Int
    unitAt :: Int -> IO Int
unitAt Int
i = Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16 -> Int) -> IO Word16 -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr Word8 -> Int -> IO Word16
peekWord16LE Ptr Word8
p Int
i
    {-# INLINE unitAt #-}
    -- Four code units, little-endian, in one word.
    word64At :: Int -> IO Word64
    word64At :: Int -> IO Word64
word64At Int
i = Ptr Word8 -> Int -> IO Word64
peekWord64LE Ptr Word8
p Int
i
    {-# INLINE word64At #-}
    -- Four little-endian code units, all below 0x80.
    asciiUnits :: a -> Bool
asciiUnits a
w = a
w a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0xFF80FF80FF80FF80 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0
    -- The low bytes of four little-endian 16-bit units, as four bytes.
    narrow :: Word64 -> Word64
    narrow :: Word64 -> Word64
narrow Word64
x0 =
      let x1 :: Word64
x1 = (Word64
x0 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
x0 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
8)) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0x0000FFFF0000FFFF
       in (Word64
x1 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
x1 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
16)) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xFFFFFFFF

-- | The most UTF-8 that @n@ bytes of UTF-16 can decode to, after @o@
-- bytes: three per code unit, and three for a trailing byte; plus one
-- byte of slack, for a three-byte sequence written as four.
maxLength :: Int -> Int -> Int
maxLength :: Int -> Int -> Int
maxLength Int
o Int
n = Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3 Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
n Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (if Int -> Bool
forall a. Integral a => a -> Bool
odd Int
n then Int
3 else Int
0) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
{-# INLINE maxLength #-}

writeW8 :: A.MArray RealWorld -> Int -> Word8 -> IO ()
writeW8 :: MArray RealWorld -> Int -> Word8 -> IO ()
writeW8 MArray RealWorld
marr Int
o Word8
w = ST RealWorld () -> IO ()
forall a. ST RealWorld a -> IO a
stToIO (MArray RealWorld -> Int -> Word8 -> ST RealWorld ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray RealWorld
marr Int
o Word8
w)
{-# INLINE writeW8 #-}

-- | Four bytes at a byte offset (unaligned), in the machine's order.
writeW32 :: A.MArray RealWorld -> Int -> Word32 -> IO ()
writeW32 :: MArray RealWorld -> Int -> Word32 -> IO ()
writeW32 (MutableByteArray MutableByteArray# RealWorld
mba) (I# Int#
o) (W32# Word32#
w) = (State# RealWorld -> (# State# RealWorld, () #)) -> IO ()
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld -> (# State# RealWorld, () #)) -> IO ())
-> (State# RealWorld -> (# State# RealWorld, () #)) -> IO ()
forall a b. (a -> b) -> a -> b
$ \State# RealWorld
s -> (# MutableByteArray# RealWorld
-> Int# -> Word32# -> State# RealWorld -> State# RealWorld
forall d.
MutableByteArray# d -> Int# -> Word32# -> State# d -> State# d
writeWord8ArrayAsWord32# MutableByteArray# RealWorld
mba Int#
o Word32#
w State# RealWorld
s, () #)
{-# INLINE writeW32 #-}

-- | Eight bytes at a byte offset (unaligned), in the machine's order.
writeW64 :: A.MArray RealWorld -> Int -> Word64 -> IO ()
writeW64 :: MArray RealWorld -> Int -> Word64 -> IO ()
writeW64 (MutableByteArray MutableByteArray# RealWorld
mba) (I# Int#
o) (W64# Word64#
w) = (State# RealWorld -> (# State# RealWorld, () #)) -> IO ()
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld -> (# State# RealWorld, () #)) -> IO ())
-> (State# RealWorld -> (# State# RealWorld, () #)) -> IO ()
forall a b. (a -> b) -> a -> b
$ \State# RealWorld
s -> (# MutableByteArray# RealWorld
-> Int# -> Word64# -> State# RealWorld -> State# RealWorld
forall d.
MutableByteArray# d -> Int# -> Word64# -> State# d -> State# d
writeWord8ArrayAsWord64# MutableByteArray# RealWorld
mba Int#
o Word64#
w State# RealWorld
s, () #)
{-# INLINE writeW64 #-}