    -- |
    -- Module      : Foundation.Collection.Buildable
    -- License     : BSD-style
    -- Maintainer  : foundation
    -- Stability   : experimental
    -- Portability : portable
    --
    -- An interface for collections that can be built incrementally.
    --
    module Foundation.Collection.Buildable
        ( Buildable(..)
        , Builder(..)
        , BuildingState(..)
        , builderLift
        , build_
        ) where

    import           Basement.UArray
    import           Basement.UArray.Mutable
    import qualified Basement.BoxedArray as BA
    import qualified Basement.String as S
    import           Foundation.Collection.Element
    import           Basement.Compat.Base
    import           Basement.Monad
    import           Basement.MutableBuilder
    import           Basement.Compat.MonadTrans
    import           Data.Kind (Type)

    -- $setup
    -- >>> import Control.Monad.ST
    -- >>> import Basement.UArray
    -- >>> import Basement.Compat.Base
    -- >>> import Basement.OffsetSize

    -- | Collections that can be built chunk by chunk.
    --
    -- Use the 'Monad' instance of 'Builder' to chain 'append' operations
    -- and feed it into `build`:
    --
    -- >>> runST $ build 32 (append 'a' >> append 'b' >> append 'c') :: UArray Char
    -- "abc"
    class Buildable col where
        {-# MINIMAL append, build #-}

        -- | Mutable collection type used for incrementally writing chunks.
        type Mutable col :: Type -> Type

        -- | Unit of the smallest step possible in an `append` operation.
        --
        -- A UTF-8 character can have a size between 1 and 4 bytes, so this
        -- should be defined as 1 byte for collections of `Char`.
        type Step col

        append :: (PrimMonad prim) => Element col -> Builder col (Mutable col) (Step col) prim err ()

        build :: (PrimMonad prim)
              => Int -- ^ CountOf of a chunk
              -> Builder col (Mutable col) (Step col) prim err ()
              -> prim (Either err col)

    builderLift :: (Buildable c, PrimMonad prim)
                => prim a
                -> Builder c (Mutable c) (Step c) prim err a
    builderLift :: forall c (prim :: * -> *) a err.
    (Buildable c, PrimMonad prim) =>
    prim a -> Builder c (Mutable c) (Step c) prim err a
    builderLift prim a
    f = State
      (Offset (Step c),
       BuildingState c (Mutable c) (Step c) (PrimState prim), Maybe err)
      prim
      a
    -> Builder c (Mutable c) (Step c) prim err a
    forall collection (mutCollection :: * -> *) step (state :: * -> *)
           err a.
    State
      (Offset step,
       BuildingState collection mutCollection step (PrimState state),
       Maybe err)
      state
      a
    -> Builder collection mutCollection step state err a
    Builder (State
       (Offset (Step c),
        BuildingState c (Mutable c) (Step c) (PrimState prim), Maybe err)
       prim
       a
     -> Builder c (Mutable c) (Step c) prim err a)
    -> State
         (Offset (Step c),
          BuildingState c (Mutable c) (Step c) (PrimState prim), Maybe err)
         prim
         a
    -> Builder c (Mutable c) (Step c) prim err a
    forall a b. (a -> b) -> a -> b
    $ ((Offset (Step c),
      BuildingState c (Mutable c) (Step c) (PrimState prim), Maybe err)
     -> prim
          (a,
           (Offset (Step c),
            BuildingState c (Mutable c) (Step c) (PrimState prim), Maybe err)))
    -> State
         (Offset (Step c),
          BuildingState c (Mutable c) (Step c) (PrimState prim), Maybe err)
         prim
         a
    forall s (m :: * -> *) a. (s -> m (a, s)) -> State s m a
    State (((Offset (Step c),
       BuildingState c (Mutable c) (Step c) (PrimState prim), Maybe err)
      -> prim
           (a,
            (Offset (Step c),
             BuildingState c (Mutable c) (Step c) (PrimState prim), Maybe err)))
     -> State
          (Offset (Step c),
           BuildingState c (Mutable c) (Step c) (PrimState prim), Maybe err)
          prim
          a)
    -> ((Offset (Step c),
         BuildingState c (Mutable c) (Step c) (PrimState prim), Maybe err)
        -> prim
             (a,
              (Offset (Step c),
               BuildingState c (Mutable c) (Step c) (PrimState prim), Maybe err)))
    -> State
         (Offset (Step c),
          BuildingState c (Mutable c) (Step c) (PrimState prim), Maybe err)
         prim
         a
    forall a b. (a -> b) -> a -> b
    $ \(Offset (Step c)
    i, BuildingState c (Mutable c) (Step c) (PrimState prim)
    st, Maybe err
    e) -> do
        ret <- prim a
    f
        return (ret, (i, st, e))

    build_ :: (Buildable c, PrimMonad prim)
           => Int -- ^ CountOf of a chunk
           -> Builder c (Mutable c) (Step c) prim () ()
           -> prim c
    build_ :: forall c (prim :: * -> *).
    (Buildable c, PrimMonad prim) =>
    Int -> Builder c (Mutable c) (Step c) prim () () -> prim c
    build_ Int
    sizeChunksI Builder c (Mutable c) (Step c) prim () ()
    ab = (() -> c) -> (c -> c) -> Either () c -> c
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (\() -> [Char] -> c
    forall a. [Char] -> a
    internalError [Char]
    "impossible output") c -> c
    forall a. a -> a
    forall {k} (cat :: k -> k -> *) (a :: k). Category cat => cat a a
    id (Either () c -> c) -> prim (Either () c) -> prim c
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Int
    -> Builder c (Mutable c) (Step c) prim () () -> prim (Either () c)
    forall col (prim :: * -> *) err.
    (Buildable col, PrimMonad prim) =>
    Int
    -> Builder col (Mutable col) (Step col) prim err ()
    -> prim (Either err col)
    forall (prim :: * -> *) err.
    PrimMonad prim =>
    Int
    -> Builder c (Mutable c) (Step c) prim err ()
    -> prim (Either err c)
    build Int
    sizeChunksI Builder c (Mutable c) (Step c) prim () ()
    ab

    instance PrimType ty => Buildable (UArray ty) where
        type Mutable (UArray ty) = MUArray ty
        type Step (UArray ty) = ty
        append :: forall (prim :: * -> *) err.
    PrimMonad prim =>
    Element (UArray ty)
    -> Builder
         (UArray ty) (Mutable (UArray ty)) (Step (UArray ty)) prim err ()
    append = ty -> Builder (UArray ty) (MUArray ty) ty prim err ()
    Element (UArray ty)
    -> Builder
         (UArray ty) (Mutable (UArray ty)) (Step (UArray ty)) prim err ()
    forall ty (state :: * -> *) err.
    (PrimType ty, PrimMonad state) =>
    ty -> Builder (UArray ty) (MUArray ty) ty state err ()
    builderAppend
        {-# INLINE append #-}
        build :: forall (prim :: * -> *) err.
    PrimMonad prim =>
    Int
    -> Builder
         (UArray ty) (Mutable (UArray ty)) (Step (UArray ty)) prim err ()
    -> prim (Either err (UArray ty))
    build = Int
    -> Builder (UArray ty) (MUArray ty) ty prim err ()
    -> prim (Either err (UArray ty))
    Int
    -> Builder
         (UArray ty) (Mutable (UArray ty)) (Step (UArray ty)) prim err ()
    -> prim (Either err (UArray ty))
    forall ty (m :: * -> *) err.
    (PrimType ty, PrimMonad m) =>
    Int
    -> Builder (UArray ty) (MUArray ty) ty m err ()
    -> m (Either err (UArray ty))
    builderBuild
        {-# INLINE build #-}

    instance Buildable (BA.Array ty) where
        type Mutable (BA.Array ty) = BA.MArray ty
        type Step (BA.Array ty) = ty

        append :: forall (prim :: * -> *) err.
    PrimMonad prim =>
    Element (Array ty)
    -> Builder
         (Array ty) (Mutable (Array ty)) (Step (Array ty)) prim err ()
    append = ty -> Builder (Array ty) (MArray ty) ty prim err ()
    Element (Array ty)
    -> Builder
         (Array ty) (Mutable (Array ty)) (Step (Array ty)) prim err ()
    forall (state :: * -> *) ty err.
    PrimMonad state =>
    ty -> Builder (Array ty) (MArray ty) ty state err ()
    BA.builderAppend
        {-# INLINE append #-}
        build :: forall (prim :: * -> *) err.
    PrimMonad prim =>
    Int
    -> Builder
         (Array ty) (Mutable (Array ty)) (Step (Array ty)) prim err ()
    -> prim (Either err (Array ty))
    build = Int
    -> Builder (Array ty) (MArray ty) ty prim err ()
    -> prim (Either err (Array ty))
    Int
    -> Builder
         (Array ty) (Mutable (Array ty)) (Step (Array ty)) prim err ()
    -> prim (Either err (Array ty))
    forall (m :: * -> *) ty err.
    PrimMonad m =>
    Int
    -> Builder (Array ty) (MArray ty) ty m err ()
    -> m (Either err (Array ty))
    BA.builderBuild
        {-# INLINE build #-}

    instance Buildable S.String where
        type Mutable S.String = S.MutableString
        type Step S.String = Word8

        append :: forall (prim :: * -> *) err.
    PrimMonad prim =>
    Element String
    -> Builder String (Mutable String) (Step String) prim err ()
    append = Char -> Builder String MutableString Word8 prim err ()
    Element String
    -> Builder String (Mutable String) (Step String) prim err ()
    forall (state :: * -> *) err.
    PrimMonad state =>
    Char -> Builder String MutableString Word8 state err ()
    S.builderAppend
        {-# INLINE append #-}
        build :: forall (prim :: * -> *) err.
    PrimMonad prim =>
    Int
    -> Builder String (Mutable String) (Step String) prim err ()
    -> prim (Either err String)
    build = Int
    -> Builder String MutableString Word8 prim err ()
    -> prim (Either err String)
    Int
    -> Builder String (Mutable String) (Step String) prim err ()
    -> prim (Either err String)
    forall (m :: * -> *) err.
    PrimMonad m =>
    Int
    -> Builder String MutableString Word8 m err ()
    -> m (Either err String)
    S.builderBuild
        {-# INLINE build #-}