-- | -- 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 -- $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 :: * -> * -- | 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 f = Builder $ State $ \(i, st, e) -> do ret <- 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_ sizeChunksI ab = either (\() -> internalError "impossible output") id <$> build sizeChunksI ab instance PrimType ty => Buildable (UArray ty) where type Mutable (UArray ty) = MUArray ty type Step (UArray ty) = ty append = builderAppend {-# INLINE append #-} build = builderBuild {-# INLINE build #-} instance Buildable (BA.Array ty) where type Mutable (BA.Array ty) = BA.MArray ty type Step (BA.Array ty) = ty append = BA.builderAppend {-# INLINE append #-} build = BA.builderBuild {-# INLINE build #-} instance Buildable S.String where type Mutable S.String = S.MutableString type Step S.String = Word8 append = S.builderAppend {-# INLINE append #-} build = S.builderBuild {-# INLINE build #-}