-- |
-- Copyright:   (c) 2022 Andrew Lelechenko
-- Licence:     BSD3
-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>

module Data.Text.Builder.Linear.Char
  ( -- * Buffer
    (|>.)
  , (.<|)
  ) where

import qualified Data.Text.Array as A
import Data.Text.Internal.Encoding.Utf8 (utf8Length, ord2, ord3, ord4)
import Data.Text.Internal.Unsafe.Char (unsafeWrite, ord)
import GHC.ST (ST)

import Data.Text.Builder.Linear.Core

-- | Append 'Char' to a 'Buffer' by mutating it.
--
-- >>> :set -XLinearTypes
-- >>> runBuffer (\b -> b |>. 'q' |>. 'w')
-- "qw"
--
(|>.)  Buffer  Char  Buffer
infixl 6 |>.
Buffer
buffer |>. :: Buffer %1 -> Char -> Buffer
|>. Char
ch = Int
-> (forall s. MArray s -> Int -> ST s Int) -> Buffer %1 -> Buffer
appendBounded Int
4 (\MArray s
dst Int
dstOff  MArray s -> Int -> Char -> ST s Int
forall s. MArray s -> Int -> Char -> ST s Int
unsafeWrite MArray s
dst Int
dstOff Char
ch) Buffer
buffer

-- | Prepend 'Char' to a 'Buffer' by mutating it.
--
-- >>> :set -XLinearTypes
-- >>> runBuffer (\b -> 'q' .<| 'w' .<| b)
-- "qw"
--
(.<|)  Char  Buffer  Buffer
infixr 6 .<|
Char
ch .<| :: Char -> Buffer %1 -> Buffer
.<| Buffer
buffer = Int
-> (forall s. MArray s -> Int -> ST s Int)
-> (forall s. MArray s -> Int -> ST s Int)
-> Buffer
%1 -> Buffer
prependBounded
  Int
4
  (\MArray s
dst Int
dstOff  MArray s -> Int -> Char -> ST s Int
forall s. MArray s -> Int -> Char -> ST s Int
unsafePrependCharM MArray s
dst Int
dstOff Char
ch)
  (\MArray s
dst Int
dstOff  MArray s -> Int -> Char -> ST s Int
forall s. MArray s -> Int -> Char -> ST s Int
unsafeWrite MArray s
dst Int
dstOff Char
ch)
  Buffer
buffer

-- | Similar to 'Data.Text.Internal.Unsafe.Char.unsafeWrite',
-- but writes _before_ a given offset.
unsafePrependCharM :: A.MArray s  Int  Char  ST s Int
unsafePrependCharM :: forall s. MArray s -> Int -> Char -> ST s Int
unsafePrependCharM MArray s
marr Int
off Char
c = case Char -> Int
utf8Length Char
c of
  Int
1  do
    let n0 :: Word8
n0 = Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Char -> Int
ord Char
c)
    MArray s -> Int -> Word8 -> ST s ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray s
marr (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Word8
n0
    Int -> ST s Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
1
  Int
2  do
    let (Word8
n0, Word8
n1) = Char -> (Word8, Word8)
ord2 Char
c
    MArray s -> Int -> Word8 -> ST s ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray s
marr (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2) Word8
n0
    MArray s -> Int -> Word8 -> ST s ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray s
marr (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Word8
n1
    Int -> ST s Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
2
  Int
3  do
    let (Word8
n0, Word8
n1, Word8
n2) = Char -> (Word8, Word8, Word8)
ord3 Char
c
    MArray s -> Int -> Word8 -> ST s ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray s
marr (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3) Word8
n0
    MArray s -> Int -> Word8 -> ST s ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray s
marr (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2) Word8
n1
    MArray s -> Int -> Word8 -> ST s ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray s
marr (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Word8
n2
    Int -> ST s Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
3
  Int
_  do
    let (Word8
n0, Word8
n1, Word8
n2, Word8
n3) = Char -> (Word8, Word8, Word8, Word8)
ord4 Char
c
    MArray s -> Int -> Word8 -> ST s ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray s
marr (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
4) Word8
n0
    MArray s -> Int -> Word8 -> ST s ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray s
marr (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
3) Word8
n1
    MArray s -> Int -> Word8 -> ST s ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray s
marr (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2) Word8
n2
    MArray s -> Int -> Word8 -> ST s ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray s
marr (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Word8
n3
    Int -> ST s Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
4