    {-# LANGUAGE CPP #-}
    {-# OPTIONS_GHC -Wno-unused-top-binds #-}

    module TextBuilderCore
      ( TextBuilder (..),

        -- * Destructors
        isEmpty,
        toText,

        -- * Constructors

        -- ** Text
        string,
        text,
        lazyText,

        -- ** Character
        char,
        unicodeCodepoint,

        -- ** Primitives
        unsafeChars,
        unsafeSeptets,
        unsafeReverseSeptets,
      )
    where

    import qualified Data.Text as Text
    import qualified Data.Text.Array as TextArray
    import qualified Data.Text.Internal as TextInternal
    import qualified Data.Text.Lazy as TextLazy
    import TextBuilderCore.Prelude

    #if MIN_VERSION_text(2,0,0)
    import qualified TextBuilderCore.Utf8View as Utf8View
    #else
    import qualified TextBuilderCore.Utf16View as Utf16View
    #endif

    -- |
    -- Composable specification of how to efficiently construct strict 'Text'.
    --
    -- Provides instances of 'Semigroup' and 'Monoid', which have complexity of /O(1)/.
    data TextBuilder
      = TextBuilder
          -- | Estimated maximum size of the byte array to allocate.
          --
          -- If the builder is empty it must be 0.
          -- Otherwise it must be greater than or equal to the amount of bytes to be written.
          --
          -- __Warning:__ Due to \"text\" switching from UTF-16 to UTF-8 since version 2, 'Word16' is used as the byte when the \"text\" version is @<2@ and 'Word8' is used when it's @>=2@.
          Int
          -- | Function that populates a preallocated byte array of the estimated maximum size specified above provided an offset into it and producing the offset after.
          --
          -- __Warning:__ The function must not write outside of the allocated array or bad things will happen to the running app.
          --
          -- __Warning:__ Keep in mind that the array is operating on 'Word8' values starting from @text-2.0@, but prior to it it operates on 'Word16'. This is due to the \"text\" library switching from UTF-16 to UTF-8 after version 2. To deal with this you have the following options:
          --
          -- 1. Restrict the version of the \"text\" library in your package to @>=2@.
          --
          -- 2. Use helpers provided by this library, such as 'unsafeSeptets' and 'unsafeReverseSeptets', which abstract over the differences in the underlying representation.
          --
          -- 3. Use CPP to conditionally compile your code for different versions of \"text\".
          (forall s. TextArray.MArray s -> Int -> ST s Int)

    instance IsString TextBuilder where
      fromString :: String -> TextBuilder
    fromString = String -> TextBuilder
    string

    instance Show TextBuilder where
      show :: TextBuilder -> String
    show = Text -> String
    forall a. Show a => a -> String
    show (Text -> String) -> (TextBuilder -> Text) -> TextBuilder -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . TextBuilder -> Text
    toText

    instance Eq TextBuilder where
      == :: TextBuilder -> TextBuilder -> Bool
    (==) = (Text -> Text -> Bool)
    -> (TextBuilder -> Text) -> TextBuilder -> TextBuilder -> Bool
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    on Text -> Text -> Bool
    forall a. Eq a => a -> a -> Bool
    (==) TextBuilder -> Text
    toText

    instance Semigroup TextBuilder where
      {-# INLINE (<>) #-}
      <> :: TextBuilder -> TextBuilder -> TextBuilder
    (<>) (TextBuilder Int
    estimatedArraySizeL forall s. MArray s -> Int -> ST s Int
    writeL) (TextBuilder Int
    estimatedArraySizeR forall s. MArray s -> Int -> ST s Int
    writeR) =
        Int -> (forall s. MArray s -> Int -> ST s Int) -> TextBuilder
    TextBuilder
          (Int
    estimatedArraySizeL Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    estimatedArraySizeR)
          ( \MArray s
    array Int
    offset -> do
              offsetAfter1 <- MArray s -> Int -> ST s Int
    forall s. MArray s -> Int -> ST s Int
    writeL MArray s
    array Int
    offset
              writeR array offsetAfter1
          )
      stimes :: forall b. Integral b => b -> TextBuilder -> TextBuilder
    stimes b
    n (TextBuilder Int
    maxSize forall s. MArray s -> Int -> ST s Int
    write) =
        Int -> (forall s. MArray s -> Int -> ST s Int) -> TextBuilder
    TextBuilder
          (Int
    maxSize Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * b -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral b
    n)
          ( \MArray s
    array ->
              let go :: b -> Int -> ST s Int
    go b
    n Int
    offset =
                    if b
    n b -> b -> Bool
    forall a. Ord a => a -> a -> Bool
    > b
    0
                      then do
                        offset <- MArray s -> Int -> ST s Int
    forall s. MArray s -> Int -> ST s Int
    write MArray s
    array Int
    offset
                        go (pred n) offset
                      else Int -> ST s Int
    forall a. a -> ST s a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Int
    offset
               in b -> Int -> ST s Int
    go b
    n
          )

    instance Monoid TextBuilder where
      {-# INLINE mempty #-}
      mempty :: TextBuilder
    mempty = Int -> (forall s. MArray s -> Int -> ST s Int) -> TextBuilder
    TextBuilder Int
    0 ((Int -> ST s Int) -> MArray s -> Int -> ST s Int
    forall a b. a -> b -> a
    const Int -> ST s Int
    forall a. a -> ST s a
    forall (m :: * -> *) a. Monad m => a -> m a
    return)
      {-# INLINE mconcat #-}
      mconcat :: [TextBuilder] -> TextBuilder
    mconcat [TextBuilder]
    list =
        Int -> (forall s. MArray s -> Int -> ST s Int) -> TextBuilder
    TextBuilder
          ((Int -> TextBuilder -> Int) -> Int -> [TextBuilder] -> Int
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' (\Int
    acc (TextBuilder Int
    maxSize forall s. MArray s -> Int -> ST s Int
    _) -> Int
    acc Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    maxSize) Int
    0 [TextBuilder]
    list)
          ( \MArray s
    array ->
              let go :: [TextBuilder] -> Int -> ST s Int
    go [] Int
    offset = Int -> ST s Int
    forall a. a -> ST s a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Int
    offset
                  go (TextBuilder Int
    _ forall s. MArray s -> Int -> ST s Int
    write : [TextBuilder]
    xs) Int
    offset = do
                    offsetAfter <- MArray s -> Int -> ST s Int
    forall s. MArray s -> Int -> ST s Int
    write MArray s
    array Int
    offset
                    go xs offsetAfter
               in [TextBuilder] -> Int -> ST s Int
    go [TextBuilder]
    list
          )

    instance Arbitrary TextBuilder where
      arbitrary :: Gen TextBuilder
    arbitrary = Text -> TextBuilder
    text (Text -> TextBuilder) -> (String -> Text) -> String -> TextBuilder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . String -> Text
    Text.pack (String -> TextBuilder) -> Gen String -> Gen TextBuilder
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Gen String
    forall a. Arbitrary a => Gen a
    arbitrary
      shrink :: TextBuilder -> [TextBuilder]
    shrink TextBuilder
    a = Text -> TextBuilder
    text (Text -> TextBuilder) -> (String -> Text) -> String -> TextBuilder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . String -> Text
    Text.pack (String -> TextBuilder) -> [String] -> [TextBuilder]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> [String]
    forall a. Arbitrary a => a -> [a]
    shrink (Text -> String
    Text.unpack (TextBuilder -> Text
    toText TextBuilder
    a))

    -- * Destructors

    -- | Execute the builder producing a strict text.
    toText :: TextBuilder -> Text
    toText :: TextBuilder -> Text
    toText (TextBuilder Int
    maxSize forall s. MArray s -> Int -> ST s Int
    write) =
      (forall s. ST s Text) -> Text
    forall a. (forall s. ST s a) -> a
    runST ((forall s. ST s Text) -> Text) -> (forall s. ST s Text) -> Text
    forall a b. (a -> b) -> a -> b
    $ do
        array <- Int -> ST s (MArray s)
    forall s. Int -> ST s (MArray s)
    TextArray.new Int
    maxSize
        offsetAfter <- write array 0
        frozenArray <- TextArray.unsafeFreeze array
        return $ TextInternal.text frozenArray 0 offsetAfter

    -- | Check whether the builder is empty.
    {-# INLINE isEmpty #-}
    isEmpty :: TextBuilder -> Bool
    isEmpty :: TextBuilder -> Bool
    isEmpty (TextBuilder Int
    maxSize forall s. MArray s -> Int -> ST s Int
    _) = Int
    maxSize Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    0

    -- * Constructors

    -- | Construct from a list of characters.
    {-# INLINE string #-}
    string :: String -> TextBuilder
    string :: String -> TextBuilder
    string String
    string =
      Int -> String -> TextBuilder
    unsafeChars (String -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length String
    string) String
    string

    -- | Strict text.
    {-# INLINEABLE text #-}
    text :: Text -> TextBuilder
    #if MIN_VERSION_text(2,0,0)
    text :: Text -> TextBuilder
    text (TextInternal.Text Array
    array Int
    offset Int
    length) =
      Int -> (forall s. MArray s -> Int -> ST s Int) -> TextBuilder
    TextBuilder Int
    length \MArray s
    builderArray Int
    builderOffset -> do
        Int -> MArray s -> Int -> Array -> Int -> ST s ()
    forall s. Int -> MArray s -> Int -> Array -> Int -> ST s ()
    TextArray.copyI Int
    length MArray s
    builderArray Int
    builderOffset Array
    array Int
    offset
        Int -> ST s Int
    forall a. a -> ST s a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Int -> ST s Int) -> Int -> ST s Int
    forall a b. (a -> b) -> a -> b
    $ Int
    builderOffset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    length
    #else
    text (TextInternal.Text array offset length) =
      TextBuilder length \builderArray builderOffset -> do
        let builderOffsetAfter = builderOffset + length
        TextArray.copyI builderArray builderOffset array offset builderOffsetAfter
        return builderOffsetAfter
    #endif

    -- | Lazy text.
    {-# INLINE lazyText #-}
    lazyText :: TextLazy.Text -> TextBuilder
    lazyText :: Text -> TextBuilder
    lazyText =
      (Text -> TextBuilder -> TextBuilder)
    -> TextBuilder -> Text -> TextBuilder
    forall a. (Text -> a -> a) -> a -> Text -> a
    TextLazy.foldrChunks (TextBuilder -> TextBuilder -> TextBuilder
    forall a. Monoid a => a -> a -> a
    mappend (TextBuilder -> TextBuilder -> TextBuilder)
    -> (Text -> TextBuilder) -> Text -> TextBuilder -> TextBuilder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Text -> TextBuilder
    text) TextBuilder
    forall a. Monoid a => a
    mempty

    -- ** Codepoint

    -- | Unicode character.
    {-# INLINE char #-}
    char :: Char -> TextBuilder
    char :: Char -> TextBuilder
    char = Int -> TextBuilder
    unicodeCodepoint (Int -> TextBuilder) -> (Char -> Int) -> Char -> TextBuilder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Char -> Int
    ord

    -- | Safe Unicode codepoint with invalid values replaced by the @�@ char (codepoint @0xfffd@),
    -- which is the same as what @Data.Text.'Data.Text.pack'@ does.
    {-# INLINE unicodeCodepoint #-}
    unicodeCodepoint :: Int -> TextBuilder
    unicodeCodepoint :: Int -> TextBuilder
    unicodeCodepoint = Int -> TextBuilder
    unsafeUnicodeCodepoint (Int -> TextBuilder) -> (Int -> Int) -> Int -> TextBuilder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Int -> Int
    forall {a}. (Bits a, Num a) => a -> a
    project
      where
        project :: a -> a
    project a
    x =
          if a
    x a -> a -> a
    forall a. Bits a => a -> a -> a
    .&. a
    0x1ff800 a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    /= a
    0xd800
            then a
    x
            else a
    0xfffd

    -- | Unicode codepoint.
    --
    -- __Warning:__ It is your responsibility to ensure that the codepoint is in proper range,
    -- otherwise the produced text will be broken.
    -- It must be in the range of 0x0000 to 0x10FFFF.
    {-# INLINE unsafeUnicodeCodepoint #-}
    unsafeUnicodeCodepoint :: Int -> TextBuilder
    #if MIN_VERSION_text(2,0,0)
    unsafeUnicodeCodepoint :: Int -> TextBuilder
    unsafeUnicodeCodepoint Int
    x =
      Int -> Utf8View
    Utf8View.unicodeCodepoint Int
    x Word8 -> TextBuilder
    unsafeUtf8CodeUnits1 Word8 -> Word8 -> TextBuilder
    unsafeUtf8CodeUnits2 Word8 -> Word8 -> Word8 -> TextBuilder
    unsafeUtf8CodeUnits3 Word8 -> Word8 -> Word8 -> Word8 -> TextBuilder
    unsafeUtf8CodeUnits4
    #else
    unsafeUnicodeCodepoint x =
      Utf16View.unicodeCodepoint x unsafeUtf16CodeUnits1 unsafeUtf16CodeUnits2
    #endif

    -- | Single code-unit UTF-8 character.
    unsafeUtf8CodeUnits1 :: Word8 -> TextBuilder
    #if MIN_VERSION_text(2,0,0)
    {-# INLINEABLE unsafeUtf8CodeUnits1 #-}
    unsafeUtf8CodeUnits1 :: Word8 -> TextBuilder
    unsafeUtf8CodeUnits1 Word8
    unit1 =
      Int -> (forall s. MArray s -> Int -> ST s Int) -> TextBuilder
    TextBuilder Int
    1 \MArray s
    array Int
    offset ->
        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array Int
    offset Word8
    unit1
          ST s () -> Int -> ST s Int
    forall (f :: * -> *) a b. Functor f => f a -> b -> f b
    $> Int -> Int
    forall a. Enum a => a -> a
    succ Int
    offset
    #else
    {-# INLINE unsafeUtf8CodeUnits1 #-}
    unsafeUtf8CodeUnits1 unit1 =
      Utf16View.utf8CodeUnits1 unit1 unsafeUtf16CodeUnits1 unsafeUtf16CodeUnits2
    #endif

    -- | Double code-unit UTF-8 character.
    unsafeUtf8CodeUnits2 :: Word8 -> Word8 -> TextBuilder
    #if MIN_VERSION_text(2,0,0)
    {-# INLINEABLE unsafeUtf8CodeUnits2 #-}
    unsafeUtf8CodeUnits2 :: Word8 -> Word8 -> TextBuilder
    unsafeUtf8CodeUnits2 Word8
    unit1 Word8
    unit2 =
      Int -> (forall s. MArray s -> Int -> ST s Int) -> TextBuilder
    TextBuilder Int
    2 \MArray s
    array Int
    offset -> do
        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array Int
    offset Word8
    unit1
        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array (Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1) Word8
    unit2
        Int -> ST s Int
    forall a. a -> ST s a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Int -> ST s Int) -> Int -> ST s Int
    forall a b. (a -> b) -> a -> b
    $ Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    2
    #else
    {-# INLINE unsafeUtf8CodeUnits2 #-}
    unsafeUtf8CodeUnits2 unit1 unit2 =
      Utf16View.utf8CodeUnits2 unit1 unit2 unsafeUtf16CodeUnits1 unsafeUtf16CodeUnits2
    #endif

    -- | Triple code-unit UTF-8 character.
    unsafeUtf8CodeUnits3 :: Word8 -> Word8 -> Word8 -> TextBuilder
    #if MIN_VERSION_text(2,0,0)
    {-# INLINEABLE unsafeUtf8CodeUnits3 #-}
    unsafeUtf8CodeUnits3 :: Word8 -> Word8 -> Word8 -> TextBuilder
    unsafeUtf8CodeUnits3 Word8
    unit1 Word8
    unit2 Word8
    unit3 =
      Int -> (forall s. MArray s -> Int -> ST s Int) -> TextBuilder
    TextBuilder Int
    3 \MArray s
    array Int
    offset -> do
        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array Int
    offset Word8
    unit1
        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array (Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1) Word8
    unit2
        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array (Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    2) Word8
    unit3
        Int -> ST s Int
    forall a. a -> ST s a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Int -> ST s Int) -> Int -> ST s Int
    forall a b. (a -> b) -> a -> b
    $ Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    3
    #else
    {-# INLINE unsafeUtf8CodeUnits3 #-}
    unsafeUtf8CodeUnits3 unit1 unit2 unit3 =
      Utf16View.utf8CodeUnits3 unit1 unit2 unit3 unsafeUtf16CodeUnits1 unsafeUtf16CodeUnits2
    #endif

    -- | UTF-8 character out of 4 code units.
    unsafeUtf8CodeUnits4 :: Word8 -> Word8 -> Word8 -> Word8 -> TextBuilder
    #if MIN_VERSION_text(2,0,0)
    {-# INLINEABLE unsafeUtf8CodeUnits4 #-}
    unsafeUtf8CodeUnits4 :: Word8 -> Word8 -> Word8 -> Word8 -> TextBuilder
    unsafeUtf8CodeUnits4 Word8
    unit1 Word8
    unit2 Word8
    unit3 Word8
    unit4 =
      Int -> (forall s. MArray s -> Int -> ST s Int) -> TextBuilder
    TextBuilder Int
    4 \MArray s
    array Int
    offset -> do
        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array Int
    offset Word8
    unit1
        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array (Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1) Word8
    unit2
        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array (Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    2) Word8
    unit3
        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array (Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    3) Word8
    unit4
        Int -> ST s Int
    forall a. a -> ST s a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Int -> ST s Int) -> Int -> ST s Int
    forall a b. (a -> b) -> a -> b
    $ Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    4
    #else
    {-# INLINE unsafeUtf8CodeUnits4 #-}
    unsafeUtf8CodeUnits4 unit1 unit2 unit3 unit4 =
      Utf16View.utf8CodeUnits4 unit1 unit2 unit3 unit4 unsafeUtf16CodeUnits1 unsafeUtf16CodeUnits2
    #endif

    -- | Single code-unit UTF-16 character.
    unsafeUtf16CodeUnits1 :: Word16 -> TextBuilder
    #if MIN_VERSION_text(2,0,0)
    {-# INLINE unsafeUtf16CodeUnits1 #-}
    unsafeUtf16CodeUnits1 :: Word16 -> TextBuilder
    unsafeUtf16CodeUnits1 = Int -> TextBuilder
    unsafeUnicodeCodepoint (Int -> TextBuilder) -> (Word16 -> Int) -> Word16 -> TextBuilder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Word16 -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral
    #else
    {-# INLINEABLE unsafeUtf16CodeUnits1 #-}
    unsafeUtf16CodeUnits1 unit =
      TextBuilder 1 \array offset ->
        TextArray.unsafeWrite array offset unit
          $> succ offset
    #endif

    -- | Double code-unit UTF-16 character.
    unsafeUtf16CodeUnits2 :: Word16 -> Word16 -> TextBuilder
    #if MIN_VERSION_text(2,0,0)
    {-# INLINE unsafeUtf16CodeUnits2 #-}
    unsafeUtf16CodeUnits2 :: Word16 -> Word16 -> TextBuilder
    unsafeUtf16CodeUnits2 Word16
    unit1 Word16
    unit2 = Int -> TextBuilder
    unsafeUnicodeCodepoint Int
    cp
      where
        cp :: Int
    cp = (((Word16 -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word16
    unit1 Int -> Int -> Int
    forall a. Bits a => a -> a -> a
    .&. Int
    0x3FF) Int -> Int -> Int
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    10) Int -> Int -> Int
    forall a. Bits a => a -> a -> a
    .|. (Word16 -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word16
    unit2 Int -> Int -> Int
    forall a. Bits a => a -> a -> a
    .&. Int
    0x3FF)) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    0x10000
    #else
    {-# INLINEABLE unsafeUtf16CodeUnits2 #-}
    unsafeUtf16CodeUnits2 unit1 unit2 =
      TextBuilder 2 \array offset -> do
        TextArray.unsafeWrite array offset unit1
        TextArray.unsafeWrite array (succ offset) unit2
        return $ offset + 2
    #endif

    -- * Basic Unsafe Primitives

    -- |
    -- Helper for constructing from char producers a bit more efficiently than via @(text . fromString)@.
    --
    -- >>> unsafeChars 3 "123"
    -- "123"
    --
    -- >>> unsafeChars 4 "123"
    -- "123"
    {-# INLINE unsafeChars #-}
    unsafeChars ::
      -- | Maximum size of the provided list of characters.
      --
      -- __Warning__: Must be greater than or equal to the length of the list.
      Int ->
      [Char] ->
      TextBuilder
    #if MIN_VERSION_text(2,0,0)
    unsafeChars :: Int -> String -> TextBuilder
    unsafeChars Int
    maxChars String
    chars =
      Int -> (forall s. MArray s -> Int -> ST s Int) -> TextBuilder
    TextBuilder
        (Int
    maxChars Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    4)
        ( \MArray s
    array ->
            (Char -> (Int -> ST s Int) -> Int -> ST s Int)
    -> (Int -> ST s Int) -> String -> Int -> ST s Int
    forall a b. (a -> b -> b) -> b -> [a] -> b
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    foldr
              ( \Char
    char Int -> ST s Int
    next Int
    offset ->
                  Int -> Utf8View
    Utf8View.unicodeCodepoint
                    (Char -> Int
    ord Char
    char)
                    ( \Word8
    byte -> do
                        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array Int
    offset Word8
    byte
                        Int -> ST s Int
    next (Int -> Int
    forall a. Enum a => a -> a
    succ Int
    offset)
                    )
                    ( \Word8
    byte1 Word8
    byte2 -> do
                        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array Int
    offset Word8
    byte1
                        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array (Int -> Int
    forall a. Enum a => a -> a
    succ Int
    offset) Word8
    byte2
                        Int -> ST s Int
    next (Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    2)
                    )
                    ( \Word8
    byte1 Word8
    byte2 Word8
    byte3 -> do
                        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array Int
    offset Word8
    byte1
                        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array (Int -> Int
    forall a. Enum a => a -> a
    succ Int
    offset) Word8
    byte2
                        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array (Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    2) Word8
    byte3
                        Int -> ST s Int
    next (Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    3)
                    )
                    ( \Word8
    byte1 Word8
    byte2 Word8
    byte3 Word8
    byte4 -> do
                        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array Int
    offset Word8
    byte1
                        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array (Int -> Int
    forall a. Enum a => a -> a
    succ Int
    offset) Word8
    byte2
                        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array (Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    2) Word8
    byte3
                        MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array (Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    3) Word8
    byte4
                        Int -> ST s Int
    next (Int
    offset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    4)
                    )
              )
              Int -> ST s Int
    forall a. a -> ST s a
    forall (m :: * -> *) a. Monad m => a -> m a
    return
              String
    chars
        )
    #else
    unsafeChars maxChars chars =
      TextBuilder
        (maxChars * 2)
        ( \array ->
            foldr
              ( \char next offset ->
                  Utf16View.unicodeCodepoint
                    (ord char)
                    ( \byte -> do
                        TextArray.unsafeWrite array offset byte
                        next (succ offset)
                    )
                    ( \byte1 byte2 -> do
                        TextArray.unsafeWrite array offset byte1
                        TextArray.unsafeWrite array (succ offset) byte2
                        next (offset + 2)
                    )
              )
              return
              chars
        )
    #endif

    -- |
    -- Provides a unified way to deal with the byte array regardless of the version of the @text@ library.
    --
    -- Keep in mind that prior to @text-2.0@, the array was operating on 'Word16' values due to the library abstracting over @UTF-16@.
    -- Starting from @text-2.0@, the array operates on 'Word8' values and the library abstracts over @UTF-8@.
    --
    -- This function is useful for building ASCII values.
    --
    -- >>> unsafeSeptets 3 (fmap (+48) [1, 2, 3])
    -- "123"
    --
    -- >>> unsafeSeptets 4 (fmap (+48) [1, 2, 3])
    -- "123"
    {-# INLINE unsafeSeptets #-}
    unsafeSeptets ::
      -- | Maximum size of the byte array to allocate.
      --
      -- Must be greater than or equal to the length of the list.
      --
      -- __Warning:__ If it is smaller, bad things will happen.
      -- We'll be writing outside of the allocated array.
      Int ->
      -- | List of bytes to write.
      --
      -- __Warning:__ It is your responsibility to ensure that the bytes are smaller than 128.
      -- Otherwise the produced text will have a broken encoding.
      --
      -- To ensure of optimization kicking in it is advised to construct the list using 'GHC.List.build'.
      [Word8] ->
      TextBuilder
    #if MIN_VERSION_text(2,0,0)
    unsafeSeptets :: Int -> [Word8] -> TextBuilder
    unsafeSeptets Int
    maxSize [Word8]
    bytes =
      Int -> (forall s. MArray s -> Int -> ST s Int) -> TextBuilder
    TextBuilder
        Int
    maxSize
        ( \MArray s
    array ->
            (Word8 -> (Int -> ST s Int) -> Int -> ST s Int)
    -> (Int -> ST s Int) -> [Word8] -> Int -> ST s Int
    forall a b. (a -> b -> b) -> b -> [a] -> b
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    foldr
              ( \Word8
    byte Int -> ST s Int
    next Int
    offset -> do
                  MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array Int
    offset Word8
    byte
                  Int -> ST s Int
    next (Int -> Int
    forall a. Enum a => a -> a
    succ Int
    offset)
              )
              Int -> ST s Int
    forall a. a -> ST s a
    forall (m :: * -> *) a. Monad m => a -> m a
    return
              [Word8]
    bytes
        )
    #else
    unsafeSeptets maxSize bytes =
      TextBuilder
        maxSize
        ( \array ->
            foldr
              ( \byte next offset -> do
                  TextArray.unsafeWrite array offset (fromIntegral byte)
                  next (succ offset)
              )
              return
              bytes
        )
    #endif

    -- | Same as 'unsafeSeptets', but writes the bytes in reverse order and requires the size to be precise.
    --
    -- >>> unsafeReverseSeptets 3 (fmap (+48) [1, 2, 3])
    -- "321"
    {-# INLINE unsafeReverseSeptets #-}
    unsafeReverseSeptets ::
      -- | Precise amount of bytes in the list.
      --
      -- Needs to be precise, because writing happens in reverse order.
      --
      -- __Warning:__ If it is smaller, bad things will happen.
      -- We'll be writing outside of the allocated array.
      Int ->
      -- | List of bytes to write in reverse order.
      --
      -- __Warning:__ It is your responsibility to ensure that the bytes are smaller than 128.
      -- Otherwise the produced text will have a broken encoding.
      --
      -- To ensure of optimization kicking in it is advised to construct the list using 'GHC.List.build'.
      [Word8] ->
      TextBuilder
    #if MIN_VERSION_text(2,0,0)
    unsafeReverseSeptets :: Int -> [Word8] -> TextBuilder
    unsafeReverseSeptets Int
    preciseSize [Word8]
    bytes =
      Int -> (forall s. MArray s -> Int -> ST s Int) -> TextBuilder
    TextBuilder
        Int
    preciseSize
        ( \MArray s
    array Int
    startOffset ->
            let endOffset :: Int
    endOffset = Int
    startOffset Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    preciseSize
             in (Word8 -> (Int -> ST s Int) -> Int -> ST s Int)
    -> (Int -> ST s Int) -> [Word8] -> Int -> ST s Int
    forall a b. (a -> b -> b) -> b -> [a] -> b
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    foldr
                  ( \Word8
    byte Int -> ST s Int
    next Int
    offset -> do
                      MArray s -> Int -> Word8 -> ST s ()
    forall s. MArray s -> Int -> Word8 -> ST s ()
    TextArray.unsafeWrite MArray s
    array Int
    offset Word8
    byte
                      Int -> ST s Int
    next (Int -> Int
    forall a. Enum a => a -> a
    pred Int
    offset)
                  )
                  (\Int
    _ -> Int -> ST s Int
    forall a. a -> ST s a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Int
    endOffset)
                  [Word8]
    bytes
                  (Int -> Int
    forall a. Enum a => a -> a
    pred Int
    endOffset)
        )
    #else
    unsafeReverseSeptets preciseSize bytes =
      TextBuilder
        preciseSize
        ( \array startOffset ->
            let endOffset = startOffset + preciseSize
             in foldr
                  ( \byte next offset -> do
                      TextArray.unsafeWrite array offset (fromIntegral byte)
                      next (pred offset)
                  )
                  (\_ -> return endOffset)
                  bytes
                  (pred endOffset)
        )
    #endif