    -- |
    -- Module      : Foundation.Array.Mutable
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : portable
    --
    module Foundation.Collection.Mutable
        ( MutableCollection(..)
        ) where

    import           Basement.Monad
    import           Basement.Types.OffsetSize
    import qualified Basement.Block         as BLK
    import qualified Basement.Block.Mutable as BLK

    import qualified Basement.UArray.Mutable as MUV
    import qualified Basement.UArray as UV
    import qualified Basement.BoxedArray as BA

    -- | Collection of things that can be made mutable, modified and then freezed into an MutableFreezed collection
    class MutableCollection c where
        -- unfortunately: cannot set mutUnsafeWrite to default to mutWrite .. same for read..
        {-# MINIMAL thaw, freeze, mutNew, mutWrite, mutRead, mutUnsafeWrite, mutUnsafeRead #-}
        type MutableFreezed c
        type MutableKey c
        type MutableValue c

        unsafeThaw   :: PrimMonad prim => MutableFreezed c -> prim (c (PrimState prim))
        unsafeThaw = MutableFreezed c -> prim (c (PrimState prim))
    forall (c :: * -> *) (prim :: * -> *).
    (MutableCollection c, PrimMonad prim) =>
    MutableFreezed c -> prim (c (PrimState prim))
    thaw
        unsafeFreeze :: PrimMonad prim => c (PrimState prim) -> prim (MutableFreezed c)
        unsafeFreeze = c (PrimState prim) -> prim (MutableFreezed c)
    forall (c :: * -> *) (prim :: * -> *).
    (MutableCollection c, PrimMonad prim) =>
    c (PrimState prim) -> prim (MutableFreezed c)
    freeze

        thaw   :: PrimMonad prim => MutableFreezed c -> prim (c (PrimState prim))
        freeze :: PrimMonad prim => c (PrimState prim) -> prim (MutableFreezed c)

        mutNew :: PrimMonad prim => CountOf (MutableValue c) -> prim (c (PrimState prim))

        mutUnsafeWrite :: PrimMonad prim => c (PrimState prim) -> MutableKey c -> MutableValue c -> prim ()
        mutWrite       :: PrimMonad prim => c (PrimState prim) -> MutableKey c -> MutableValue c -> prim ()
        mutUnsafeRead :: PrimMonad prim => c (PrimState prim) -> MutableKey c -> prim (MutableValue c)
        mutRead       :: PrimMonad prim => c (PrimState prim) -> MutableKey c -> prim (MutableValue c)

    instance UV.PrimType ty => MutableCollection (MUV.MUArray ty) where
        type MutableFreezed (MUV.MUArray ty) = UV.UArray ty
        type MutableKey (MUV.MUArray ty) = Offset ty
        type MutableValue (MUV.MUArray ty) = ty

        thaw :: MutableFreezed (MUArray ty) -> prim (MUArray ty (PrimState prim))
    thaw = MutableFreezed (MUArray ty) -> prim (MUArray ty (PrimState prim))
    forall (prim :: * -> *) ty.
    (PrimMonad prim, PrimType ty) =>
    UArray ty -> prim (MUArray ty (PrimState prim))
    UV.thaw
        freeze :: MUArray ty (PrimState prim) -> prim (MutableFreezed (MUArray ty))
    freeze = MUArray ty (PrimState prim) -> prim (MutableFreezed (MUArray ty))
    forall ty (prim :: * -> *).
    (PrimType ty, PrimMonad prim) =>
    MUArray ty (PrimState prim) -> prim (UArray ty)
    UV.freeze
        unsafeThaw :: MutableFreezed (MUArray ty) -> prim (MUArray ty (PrimState prim))
    unsafeThaw = MutableFreezed (MUArray ty) -> prim (MUArray ty (PrimState prim))
    forall ty (prim :: * -> *).
    (PrimType ty, PrimMonad prim) =>
    UArray ty -> prim (MUArray ty (PrimState prim))
    UV.unsafeThaw
        unsafeFreeze :: MUArray ty (PrimState prim) -> prim (MutableFreezed (MUArray ty))
    unsafeFreeze = MUArray ty (PrimState prim) -> prim (MutableFreezed (MUArray ty))
    forall (prim :: * -> *) ty.
    PrimMonad prim =>
    MUArray ty (PrimState prim) -> prim (UArray ty)
    UV.unsafeFreeze

        mutNew :: CountOf (MutableValue (MUArray ty))
    -> prim (MUArray ty (PrimState prim))
    mutNew = CountOf (MutableValue (MUArray ty))
    -> prim (MUArray ty (PrimState prim))
    forall (prim :: * -> *) ty.
    (PrimMonad prim, PrimType ty) =>
    CountOf ty -> prim (MUArray ty (PrimState prim))
    MUV.new

        mutUnsafeWrite :: MUArray ty (PrimState prim)
    -> MutableKey (MUArray ty) -> MutableValue (MUArray ty) -> prim ()
    mutUnsafeWrite = MUArray ty (PrimState prim)
    -> MutableKey (MUArray ty) -> MutableValue (MUArray ty) -> prim ()
    forall (prim :: * -> *) ty.
    (PrimMonad prim, PrimType ty) =>
    MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
    MUV.unsafeWrite
        mutUnsafeRead :: MUArray ty (PrimState prim)
    -> MutableKey (MUArray ty) -> prim (MutableValue (MUArray ty))
    mutUnsafeRead = MUArray ty (PrimState prim)
    -> MutableKey (MUArray ty) -> prim (MutableValue (MUArray ty))
    forall (prim :: * -> *) ty.
    (PrimMonad prim, PrimType ty) =>
    MUArray ty (PrimState prim) -> Offset ty -> prim ty
    MUV.unsafeRead
        mutWrite :: MUArray ty (PrimState prim)
    -> MutableKey (MUArray ty) -> MutableValue (MUArray ty) -> prim ()
    mutWrite = MUArray ty (PrimState prim)
    -> MutableKey (MUArray ty) -> MutableValue (MUArray ty) -> prim ()
    forall (prim :: * -> *) ty.
    (PrimMonad prim, PrimType ty) =>
    MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
    MUV.write
        mutRead :: MUArray ty (PrimState prim)
    -> MutableKey (MUArray ty) -> prim (MutableValue (MUArray ty))
    mutRead = MUArray ty (PrimState prim)
    -> MutableKey (MUArray ty) -> prim (MutableValue (MUArray ty))
    forall (prim :: * -> *) ty.
    (PrimMonad prim, PrimType ty) =>
    MUArray ty (PrimState prim) -> Offset ty -> prim ty
    MUV.read

    instance UV.PrimType ty => MutableCollection (BLK.MutableBlock ty) where
        type MutableFreezed (BLK.MutableBlock ty) = BLK.Block ty
        type MutableKey (BLK.MutableBlock ty) = Offset ty
        type MutableValue (BLK.MutableBlock ty) = ty

        thaw :: MutableFreezed (MutableBlock ty)
    -> prim (MutableBlock ty (PrimState prim))
    thaw = MutableFreezed (MutableBlock ty)
    -> prim (MutableBlock ty (PrimState prim))
    forall (prim :: * -> *) ty.
    (PrimMonad prim, PrimType ty) =>
    Block ty -> prim (MutableBlock ty (PrimState prim))
    BLK.thaw
        freeze :: MutableBlock ty (PrimState prim)
    -> prim (MutableFreezed (MutableBlock ty))
    freeze = MutableBlock ty (PrimState prim)
    -> prim (MutableFreezed (MutableBlock ty))
    forall ty (prim :: * -> *).
    (PrimType ty, PrimMonad prim) =>
    MutableBlock ty (PrimState prim) -> prim (Block ty)
    BLK.freeze
        unsafeThaw :: MutableFreezed (MutableBlock ty)
    -> prim (MutableBlock ty (PrimState prim))
    unsafeThaw = MutableFreezed (MutableBlock ty)
    -> prim (MutableBlock ty (PrimState prim))
    forall ty (prim :: * -> *).
    (PrimType ty, PrimMonad prim) =>
    Block ty -> prim (MutableBlock ty (PrimState prim))
    BLK.unsafeThaw
        unsafeFreeze :: MutableBlock ty (PrimState prim)
    -> prim (MutableFreezed (MutableBlock ty))
    unsafeFreeze = MutableBlock ty (PrimState prim)
    -> prim (MutableFreezed (MutableBlock ty))
    forall (prim :: * -> *) ty.
    PrimMonad prim =>
    MutableBlock ty (PrimState prim) -> prim (Block ty)
    BLK.unsafeFreeze

        mutNew :: CountOf (MutableValue (MutableBlock ty))
    -> prim (MutableBlock ty (PrimState prim))
    mutNew = CountOf (MutableValue (MutableBlock ty))
    -> prim (MutableBlock ty (PrimState prim))
    forall (prim :: * -> *) ty.
    (PrimMonad prim, PrimType ty) =>
    CountOf ty -> prim (MutableBlock ty (PrimState prim))
    BLK.new

        mutUnsafeWrite :: MutableBlock ty (PrimState prim)
    -> MutableKey (MutableBlock ty)
    -> MutableValue (MutableBlock ty)
    -> prim ()
    mutUnsafeWrite = MutableBlock ty (PrimState prim)
    -> MutableKey (MutableBlock ty)
    -> MutableValue (MutableBlock ty)
    -> prim ()
    forall (prim :: * -> *) ty.
    (PrimMonad prim, PrimType ty) =>
    MutableBlock ty (PrimState prim) -> Offset ty -> ty -> prim ()
    BLK.unsafeWrite
        mutUnsafeRead :: MutableBlock ty (PrimState prim)
    -> MutableKey (MutableBlock ty)
    -> prim (MutableValue (MutableBlock ty))
    mutUnsafeRead = MutableBlock ty (PrimState prim)
    -> MutableKey (MutableBlock ty)
    -> prim (MutableValue (MutableBlock ty))
    forall (prim :: * -> *) ty.
    (PrimMonad prim, PrimType ty) =>
    MutableBlock ty (PrimState prim) -> Offset ty -> prim ty
    BLK.unsafeRead
        mutWrite :: MutableBlock ty (PrimState prim)
    -> MutableKey (MutableBlock ty)
    -> MutableValue (MutableBlock ty)
    -> prim ()
    mutWrite = MutableBlock ty (PrimState prim)
    -> MutableKey (MutableBlock ty)
    -> MutableValue (MutableBlock ty)
    -> prim ()
    forall (prim :: * -> *) ty.
    (PrimMonad prim, PrimType ty) =>
    MutableBlock ty (PrimState prim) -> Offset ty -> ty -> prim ()
    BLK.write
        mutRead :: MutableBlock ty (PrimState prim)
    -> MutableKey (MutableBlock ty)
    -> prim (MutableValue (MutableBlock ty))
    mutRead = MutableBlock ty (PrimState prim)
    -> MutableKey (MutableBlock ty)
    -> prim (MutableValue (MutableBlock ty))
    forall (prim :: * -> *) ty.
    (PrimMonad prim, PrimType ty) =>
    MutableBlock ty (PrimState prim) -> Offset ty -> prim ty
    BLK.read

    instance MutableCollection (BA.MArray ty) where
        type MutableFreezed (BA.MArray ty) = BA.Array ty
        type MutableKey (BA.MArray ty) = Offset ty
        type MutableValue (BA.MArray ty) = ty

        thaw :: MutableFreezed (MArray ty) -> prim (MArray ty (PrimState prim))
    thaw = MutableFreezed (MArray ty) -> prim (MArray ty (PrimState prim))
    forall (prim :: * -> *) ty.
    PrimMonad prim =>
    Array ty -> prim (MArray ty (PrimState prim))
    BA.thaw
        freeze :: MArray ty (PrimState prim) -> prim (MutableFreezed (MArray ty))
    freeze = MArray ty (PrimState prim) -> prim (MutableFreezed (MArray ty))
    forall (prim :: * -> *) ty.
    PrimMonad prim =>
    MArray ty (PrimState prim) -> prim (Array ty)
    BA.freeze
        unsafeThaw :: MutableFreezed (MArray ty) -> prim (MArray ty (PrimState prim))
    unsafeThaw = MutableFreezed (MArray ty) -> prim (MArray ty (PrimState prim))
    forall (prim :: * -> *) ty.
    PrimMonad prim =>
    Array ty -> prim (MArray ty (PrimState prim))
    BA.unsafeThaw
        unsafeFreeze :: MArray ty (PrimState prim) -> prim (MutableFreezed (MArray ty))
    unsafeFreeze = MArray ty (PrimState prim) -> prim (MutableFreezed (MArray ty))
    forall (prim :: * -> *) ty.
    PrimMonad prim =>
    MArray ty (PrimState prim) -> prim (Array ty)
    BA.unsafeFreeze

        mutNew :: CountOf (MutableValue (MArray ty))
    -> prim (MArray ty (PrimState prim))
    mutNew = CountOf (MutableValue (MArray ty))
    -> prim (MArray ty (PrimState prim))
    forall (prim :: * -> *) ty.
    PrimMonad prim =>
    CountOf ty -> prim (MArray ty (PrimState prim))
    BA.new
        mutUnsafeWrite :: MArray ty (PrimState prim)
    -> MutableKey (MArray ty) -> MutableValue (MArray ty) -> prim ()
    mutUnsafeWrite = MArray ty (PrimState prim)
    -> MutableKey (MArray ty) -> MutableValue (MArray ty) -> prim ()
    forall (prim :: * -> *) ty.
    PrimMonad prim =>
    MArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
    BA.unsafeWrite
        mutUnsafeRead :: MArray ty (PrimState prim)
    -> MutableKey (MArray ty) -> prim (MutableValue (MArray ty))
    mutUnsafeRead = MArray ty (PrimState prim)
    -> MutableKey (MArray ty) -> prim (MutableValue (MArray ty))
    forall (prim :: * -> *) ty.
    PrimMonad prim =>
    MArray ty (PrimState prim) -> Offset ty -> prim ty
    BA.unsafeRead
        mutWrite :: MArray ty (PrimState prim)
    -> MutableKey (MArray ty) -> MutableValue (MArray ty) -> prim ()
    mutWrite = MArray ty (PrimState prim)
    -> MutableKey (MArray ty) -> MutableValue (MArray ty) -> prim ()
    forall (prim :: * -> *) ty.
    PrimMonad prim =>
    MArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
    BA.write
        mutRead :: MArray ty (PrimState prim)
    -> MutableKey (MArray ty) -> prim (MutableValue (MArray ty))
    mutRead = MArray ty (PrimState prim)
    -> MutableKey (MArray ty) -> prim (MutableValue (MArray ty))
    forall (prim :: * -> *) ty.
    PrimMonad prim =>
    MArray ty (PrimState prim) -> Offset ty -> prim ty
    BA.read