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

import           Foundation.Primitive.Monad
import           Foundation.Primitive.Types.OffsetSize
import qualified Foundation.Primitive.Block         as BLK
import qualified Foundation.Primitive.Block.Mutable as BLK
import           Foundation.Internal.Base

import qualified Foundation.Array.Unboxed.Mutable as MUV
import qualified Foundation.Array.Unboxed as UV
import qualified Foundation.Array.Boxed 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 = thaw
    unsafeFreeze :: PrimMonad prim => c (PrimState prim) -> prim (MutableFreezed c)
    unsafeFreeze = freeze

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

    mutNew :: PrimMonad prim => Int -> 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 = UV.thaw
    freeze = UV.freeze
    unsafeThaw = UV.unsafeThaw
    unsafeFreeze = UV.unsafeFreeze

    mutNew i = MUV.new (Size i)

    mutUnsafeWrite = MUV.unsafeWrite
    mutUnsafeRead = MUV.unsafeRead
    mutWrite = MUV.write
    mutRead = 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 = BLK.thaw
    freeze = BLK.freeze
    unsafeThaw = BLK.unsafeThaw
    unsafeFreeze = BLK.unsafeFreeze

    mutNew i = BLK.new (Size i)

    mutUnsafeWrite = BLK.unsafeWrite
    mutUnsafeRead = BLK.unsafeRead
    mutWrite = BLK.write
    mutRead = 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 = BA.thaw
    freeze = BA.freeze
    unsafeThaw = BA.unsafeThaw
    unsafeFreeze = BA.unsafeFreeze

    mutNew n = BA.new (Size n)
    mutUnsafeWrite = BA.unsafeWrite
    mutUnsafeRead = BA.unsafeRead
    mutWrite = BA.write
    mutRead = BA.read