-- | A table representation that internally uses a hashtable from the @hashtables@ library. The
-- implementation is currently a testbed on which idea makes the most sense.
--
-- In particular, once a hashtable has been created with, say, @newWithPA@, it will be completely
-- void of any entries. To prime the system, call @setValidKeys@ which will setup all keys that are
-- vaild, as well as setup an additional data structure to help with @streamUp@ and @streamDown@.
--
-- This table does not store default values, since it is assumed that lookups are only done on valid
-- keys, and @ADPfusion@ as the default consumer should have rules "jump over" missing keys.
--
-- Currently the idea is that any write to an undeclared key will just fail SILENTLY!
--
-- TODO this also forces rethinking @inBounds@, as this will now depend on the internal structure
-- given via @setValidKeys@.

module Data.PrimitiveArray.HashTable where

import Control.Monad.Primitive
import Control.Monad.ST
import Control.Monad.ST.Unsafe
import Data.HashTable.Class as HT
import Data.HashTable.IO as HTIO
import Unsafe.Coerce

import Data.PrimitiveArray.Class
import Data.PrimitiveArray.Index.Class



data Hashed ht sh e = Hashed
  { Hashed ht sh e -> LimitType sh
_hashedUpperBound :: !(LimitType sh)
    -- ^ Explicitly store the upper bound.
  , Hashed ht sh e -> IOHashTable ht sh e
_hashedTable      :: !(IOHashTable ht sh e)
    -- ^ The hashtable to be updated / used.
  , Hashed ht sh e -> ()
_hashedUpDown     :: !()
    -- ^ Helper structure for the @streamUp@ / @streamDown@ functionality.
    --
    -- TODO this should be a recursively constructed hashtable, based on the shape of @sh@.
  }



-- | Sets valid keys, working within a primitive Monad. The valid keys should be a hashtable with
-- all correct keys, but values set to something resembling a default value. A good choice will be
-- akin to @mzero@.
--
-- Internally, this function uses @unsafeCoerce@ to change the @PrimState@ token held by the hash
-- table to @RealWord@, from whatever it is.
--
-- TODO setup the @hashedUpDown@ part, once it is clear what to do.

setValidKeys
  :: (PrimMonad m, HashTable h)
  => LimitType sh
  -> h (PrimState m) k v
  -> m (Hashed ht sh e)
{-# Inline setValidKeys #-}
setValidKeys :: LimitType sh -> h (PrimState m) k v -> m (Hashed ht sh e)
setValidKeys LimitType sh
ub h (PrimState m) k v
ks = Hashed ht sh e -> m (Hashed ht sh e)
forall (m :: * -> *) a. Monad m => a -> m a
return (Hashed ht sh e -> m (Hashed ht sh e))
-> Hashed ht sh e -> m (Hashed ht sh e)
forall a b. (a -> b) -> a -> b
$ Hashed :: forall (ht :: * -> * -> * -> *) sh e.
LimitType sh -> IOHashTable ht sh e -> () -> Hashed ht sh e
Hashed
    { _hashedUpperBound :: LimitType sh
_hashedUpperBound = LimitType sh
ub
    , _hashedTable :: IOHashTable ht sh e
_hashedTable      = h (PrimState m) k v -> ht RealWorld sh e
forall a b. a -> b
unsafeCoerce h (PrimState m) k v
ks
    , _hashedUpDown :: ()
_hashedUpDown     = ()
    }