    {-# LANGUAGE UndecidableInstances #-}
    {-# LANGUAGE CPP #-}

    module Foundation.Collection.Copy
        ( Copy(..)
        ) where

    import           GHC.ST (runST)
    import           Basement.Compat.Base ((>>=))
    import           Basement.Nat
    import           Basement.Types.OffsetSize
    import qualified Basement.Block as BLK
    import qualified Basement.UArray as UA
    import qualified Basement.BoxedArray as BA
    import qualified Basement.String as S

    #if MIN_VERSION_base(4,9,0)
    import qualified Basement.Sized.Block as BLKN
    import qualified Basement.Sized.List  as LN
    #endif

    class Copy a where
        copy :: a -> a
    instance Copy [ty] where
        copy :: [ty] -> [ty]
    copy a :: [ty]
    a = [ty]
    a
    instance UA.PrimType ty => Copy (BLK.Block ty) where
        copy :: Block ty -> Block ty
    copy blk :: Block ty
    blk = (forall s. ST s (Block ty)) -> Block ty
    forall a. (forall s. ST s a) -> a
    runST (Block ty -> ST s (MutableBlock ty (PrimState (ST s)))
    forall (prim :: * -> *) ty.
    (PrimMonad prim, PrimType ty) =>
    Block ty -> prim (MutableBlock ty (PrimState prim))
    BLK.thaw Block ty
    blk ST s (MutableBlock ty s)
    -> (MutableBlock ty s -> ST s (Block ty)) -> ST s (Block ty)
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= MutableBlock ty s -> ST s (Block ty)
    forall (prim :: * -> *) ty.
    PrimMonad prim =>
    MutableBlock ty (PrimState prim) -> prim (Block ty)
    BLK.unsafeFreeze)
    instance UA.PrimType ty => Copy (UA.UArray ty) where
        copy :: UArray ty -> UArray ty
    copy = UArray ty -> UArray ty
    forall ty. PrimType ty => UArray ty -> UArray ty
    UA.copy
    instance Copy (BA.Array ty) where
        copy :: Array ty -> Array ty
    copy = Array ty -> Array ty
    forall ty. Array ty -> Array ty
    BA.copy
    instance Copy S.String where
        copy :: String -> String
    copy = String -> String
    S.copy

    #if MIN_VERSION_base(4,9,0)
    instance Copy (LN.ListN n ty) where
        copy :: ListN n ty -> ListN n ty
    copy a :: ListN n ty
    a = ListN n ty
    a
    instance (Countable ty n, UA.PrimType ty, KnownNat n) => Copy (BLKN.BlockN n ty) where
        copy :: BlockN n ty -> BlockN n ty
    copy blk :: BlockN n ty
    blk = (forall s. ST s (BlockN n ty)) -> BlockN n ty
    forall a. (forall s. ST s a) -> a
    runST (BlockN n ty -> ST s (MutableBlockN n ty (PrimState (ST s)))
    forall (n :: Nat) (prim :: * -> *) ty.
    (KnownNat n, PrimMonad prim, PrimType ty) =>
    BlockN n ty -> prim (MutableBlockN n ty (PrimState prim))
    BLKN.thaw BlockN n ty
    blk ST s (MutableBlockN n ty s)
    -> (MutableBlockN n ty s -> ST s (BlockN n ty))
    -> ST s (BlockN n ty)
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= MutableBlockN n ty s -> ST s (BlockN n ty)
    forall (prim :: * -> *) ty (n :: Nat).
    (PrimMonad prim, PrimType ty, Countable ty n) =>
    MutableBlockN n ty (PrimState prim) -> prim (BlockN n ty)
    BLKN.freeze)
    #endif