    -- |
    -- Module      : Basement.String.Builder
    -- License     : BSD-style
    -- Maintainer  : Foundation
    --
    -- String builder

    {-# LANGUAGE GeneralizedNewtypeDeriving #-}

    module Basement.String.Builder
        ( Builder
        , run
        , runUnsafe

        -- * Emit functions
        , emit
        , emitChar

        -- * unsafe
        , unsafeStringBuilder
        ) where

    import qualified Basement.Block.Base as Block (length)
    import qualified Basement.Block.Builder as Block
    import           Basement.Compat.Base
    import           Basement.Compat.Semigroup
    import           Basement.Monad
    import           Basement.String (String, ValidationFailure, Encoding (UTF8), fromBytes)
    import           Basement.UArray.Base (UArray)
    import qualified Basement.UArray.Base as A

    newtype Builder = Builder Block.Builder
      deriving (NonEmpty Builder -> Builder
    Builder -> Builder -> Builder
    (Builder -> Builder -> Builder)
    -> (NonEmpty Builder -> Builder)
    -> (forall b. Integral b => b -> Builder -> Builder)
    -> Semigroup Builder
    forall b. Integral b => b -> Builder -> Builder
    forall a.
    (a -> a -> a)
    -> (NonEmpty a -> a)
    -> (forall b. Integral b => b -> a -> a)
    -> Semigroup a
    $c<> :: Builder -> Builder -> Builder
    <> :: Builder -> Builder -> Builder
    $csconcat :: NonEmpty Builder -> Builder
    sconcat :: NonEmpty Builder -> Builder
    $cstimes :: forall b. Integral b => b -> Builder -> Builder
    stimes :: forall b. Integral b => b -> Builder -> Builder
    Semigroup, Semigroup Builder
    Builder
    Semigroup Builder =>
    Builder
    -> (Builder -> Builder -> Builder)
    -> ([Builder] -> Builder)
    -> Monoid Builder
    [Builder] -> Builder
    Builder -> Builder -> Builder
    forall a.
    Semigroup a =>
    a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
    $cmempty :: Builder
    mempty :: Builder
    $cmappend :: Builder -> Builder -> Builder
    mappend :: Builder -> Builder -> Builder
    $cmconcat :: [Builder] -> Builder
    mconcat :: [Builder] -> Builder
    Monoid)

    unsafeStringBuilder :: Block.Builder -> Builder
    unsafeStringBuilder :: Builder -> Builder
    unsafeStringBuilder = Builder -> Builder
    Builder
    {-# INLINE unsafeStringBuilder #-}

    run :: PrimMonad prim => Builder -> prim (String, Maybe ValidationFailure, UArray Word8)
    run :: forall (prim :: * -> *).
    PrimMonad prim =>
    Builder -> prim (String, Maybe ValidationFailure, UArray Word8)
    run (Builder Builder
    builder) = do
        block <- Builder -> prim (Block Word8)
    forall (prim :: * -> *).
    PrimMonad prim =>
    Builder -> prim (Block Word8)
    Block.run Builder
    builder
        let array = Offset Word8
    -> CountOf Word8 -> UArrayBackend Word8 -> UArray Word8
    forall ty. Offset ty -> CountOf ty -> UArrayBackend ty -> UArray ty
    A.UArray Offset Word8
    0 (Block Word8 -> CountOf Word8
    forall ty. PrimType ty => Block ty -> CountOf ty
    Block.length Block Word8
    block) (Block Word8 -> UArrayBackend Word8
    forall ty. Block ty -> UArrayBackend ty
    A.UArrayBA Block Word8
    block)
        pure $ fromBytes UTF8 array

    -- | run the given builder and return the generated String
    --
    -- prefer `run`
    runUnsafe :: PrimMonad prim => Builder -> prim String
    runUnsafe :: forall (prim :: * -> *). PrimMonad prim => Builder -> prim String
    runUnsafe (Builder Builder
    builder) = Builder -> prim String
    forall (prim :: * -> *). PrimMonad prim => Builder -> prim String
    Block.unsafeRunString Builder
    builder

    -- | add a string in the builder
    emit :: String -> Builder
    emit :: String -> Builder
    emit = Builder -> Builder
    Builder (Builder -> Builder) -> (String -> Builder) -> String -> Builder
    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 -> Builder
    Block.emitString

    -- | emit a UTF8 char in the builder
    emitChar :: Char -> Builder
    emitChar :: Char -> Builder
    emitChar = Builder -> Builder
    Builder (Builder -> Builder) -> (Char -> Builder) -> Char -> Builder
    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 -> Builder
    Block.emitUTF8Char