{-# LANGUAGE EmptyDataDecls #-}

module Data.MutMap
  ( -- * MutMap
    MutMap
  , mutEmpty
  , mutFromList
  , mutLookup
  , mutElems
  , mutKeys
  , mutAssocs
  , mutClone
  , mutMapM
  , mutMapM_
  , mutMapMaybeM
  , mutInsert
  , mutDelete
  , mutClear
  )
  where

import Data.Defined
import Data.MutMap.Internal
import Data.Text (Text)
import FFI
import Prelude

data MutMap a

-- Construction

mutEmpty :: Fay (MutMap a)
mutEmpty :: Fay (MutMap a)
mutEmpty = [Char] -> Fay (MutMap a)
forall s a. IsString s => s -> a
ffi [Char]
"{}"

mutFromList :: [(Text, a)] -> Fay (MutMap a)
mutFromList :: [(Text, a)] -> Fay (MutMap a)
mutFromList = [KeyValI a] -> Fay (MutMap a)
forall a. [KeyValI a] -> Fay (MutMap a)
mutFromListI ([KeyValI a] -> Fay (MutMap a))
-> ([(Text, a)] -> [KeyValI a]) -> [(Text, a)] -> Fay (MutMap a)
forall t1 t t2. (t1 -> t) -> (t2 -> t1) -> t2 -> t
. ((Text, a) -> KeyValI a) -> [(Text, a)] -> [KeyValI a]
forall a b. (a -> b) -> [a] -> [b]
map (\(Text
key, a
val) -> Salted -> a -> KeyValI a
forall a. Salted -> a -> KeyValI a
KeyValI (Text -> Salted
addSalt Text
key) a
val)

mutFromListI :: [KeyValI a] -> Fay (MutMap a)
mutFromListI :: [KeyValI a] -> Fay (MutMap a)
mutFromListI = [Char] -> [KeyValI a] -> Fay (MutMap a)
forall s a. IsString s => s -> a
ffi [Char]
"function() { var r = {}; for(var key in %1) { r[%1[key].slot1] = %1[key].slot2; } return r; }()"

-- Query

mutLookup :: Text -> MutMap a -> Fay (Maybe a)
mutLookup :: Text -> MutMap a -> Fay (Maybe a)
mutLookup Text
k MutMap a
m = Maybe a -> Fay (Maybe a)
forall a. a -> Fay a
return (Maybe a -> Fay (Maybe a))
-> (Defined a -> Maybe a) -> Defined a -> Fay (Maybe a)
forall t1 t t2. (t1 -> t) -> (t2 -> t1) -> t2 -> t
. Defined a -> Maybe a
forall a. Defined a -> Maybe a
fromDefined (Defined a -> Fay (Maybe a)) -> Fay (Defined a) -> Fay (Maybe a)
forall a b. (a -> Fay b) -> Fay a -> Fay b
=<< Salted -> MutMap a -> Fay (Defined a)
forall a. Salted -> MutMap a -> Fay (Defined a)
mutLookupI (Text -> Salted
addSalt Text
k) MutMap a
m

mutLookupI :: Salted -> MutMap a -> Fay (Defined a)
mutLookupI :: Salted -> MutMap a -> Fay (Defined a)
mutLookupI = [Char] -> Salted -> MutMap a -> Fay (Defined a)
forall s a. IsString s => s -> a
ffi [Char]
"%2[%1]"

mutElems :: MutMap a -> Fay [a]
mutElems :: MutMap a -> Fay [a]
mutElems = [Char] -> MutMap a -> Fay [a]
forall s a. IsString s => s -> a
ffi [Char]
"function() { var r = []; for (var k in %1) { r.push(%1[k]); } return r; }()"

mutKeys :: MutMap a -> Fay [Text]
mutKeys :: MutMap a -> Fay [Text]
mutKeys MutMap a
m = [Text] -> Fay [Text]
forall a. a -> Fay a
return ([Text] -> Fay [Text])
-> ([Salted] -> [Text]) -> [Salted] -> Fay [Text]
forall t1 t t2. (t1 -> t) -> (t2 -> t1) -> t2 -> t
. (Salted -> Text) -> [Salted] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map Salted -> Text
unsalt ([Salted] -> Fay [Text]) -> Fay [Salted] -> Fay [Text]
forall a b. (a -> Fay b) -> Fay a -> Fay b
=<< MutMap a -> Fay [Salted]
forall a. MutMap a -> Fay [Salted]
mutKeysI MutMap a
m

mutKeysI :: MutMap a -> Fay [Salted]
mutKeysI :: MutMap a -> Fay [Salted]
mutKeysI = [Char] -> MutMap a -> Fay [Salted]
forall s a. IsString s => s -> a
ffi [Char]
"function() { var r = []; for (var k in %1) { r.push(k); } return r; }()"

mutAssocs :: MutMap a -> Fay [(Text, a)]
mutAssocs :: MutMap a -> Fay [(Text, a)]
mutAssocs MutMap a
m = [(Text, a)] -> Fay [(Text, a)]
forall a. a -> Fay a
return ([(Text, a)] -> Fay [(Text, a)])
-> ([KeyValI a] -> [(Text, a)]) -> [KeyValI a] -> Fay [(Text, a)]
forall t1 t t2. (t1 -> t) -> (t2 -> t1) -> t2 -> t
. (KeyValI a -> (Text, a)) -> [KeyValI a] -> [(Text, a)]
forall a b. (a -> b) -> [a] -> [b]
map (\(KeyValI Salted
key a
val) -> (Salted -> Text
unsalt Salted
key, a
val)) ([KeyValI a] -> Fay [(Text, a)])
-> Fay [KeyValI a] -> Fay [(Text, a)]
forall a b. (a -> Fay b) -> Fay a -> Fay b
=<< MutMap a -> Fay [KeyValI a]
forall a. MutMap a -> Fay [KeyValI a]
mutAssocsI MutMap a
m

mutAssocsI :: MutMap a -> Fay [KeyValI a]
mutAssocsI :: MutMap a -> Fay [KeyValI a]
mutAssocsI = [Char] -> MutMap a -> Fay [KeyValI a]
forall s a. IsString s => s -> a
ffi [Char]
"function() { var r = []; for (var k in %1) { r.push({ instance : 'KeyValI', slot1 : k, slot2 : %1[k] }); } return r; }()"

mutClone :: MutMap a -> Fay (MutMap a)
mutClone :: MutMap a -> Fay (MutMap a)
mutClone = [Char] -> MutMap a -> Fay (MutMap a)
forall s a. IsString s => s -> a
ffi [Char]
"Fay$$objConcat({}, %1)"

-- Note: Also clones.
mutMapM :: (a -> Fay b) -> MutMap a -> MutMap b
mutMapM :: (a -> Fay b) -> MutMap a -> MutMap b
mutMapM = [Char] -> (a -> Fay b) -> MutMap a -> MutMap b
forall s a. IsString s => s -> a
ffi [Char]
"function () { var r = {}; for(var key in %2){ r[key] = %1(%2[key]); } return r;}()"

mutMapM_ :: (a -> Fay ()) -> MutMap a -> Fay ()
mutMapM_ :: (a -> Fay ()) -> MutMap a -> Fay ()
mutMapM_ = [Char] -> (a -> Fay ()) -> MutMap a -> Fay ()
forall s a. IsString s => s -> a
ffi [Char]
"function () { var r = {}; for(var key in %2){ %1(%2[key]); } return;}()"

-- Note: Also clones.
mutMapMaybeM :: (a -> Fay (Maybe b)) -> MutMap a -> MutMap b
mutMapMaybeM :: (a -> Fay (Maybe b)) -> MutMap a -> MutMap b
mutMapMaybeM a -> Fay (Maybe b)
f = (a -> Fay (Defined b)) -> MutMap a -> MutMap b
forall a b. (a -> Fay (Defined b)) -> MutMap a -> MutMap b
mutMapMaybeMI ((a -> Fay (Defined b)) -> MutMap a -> MutMap b)
-> (a -> Fay (Defined b)) -> MutMap a -> MutMap b
forall t1 t. (t1 -> t) -> t1 -> t
$ \a
x -> a -> Fay (Maybe b)
f a
x Fay (Maybe b)
-> Ptr (Maybe b -> Fay (Defined b)) -> Fay (Defined b)
forall a b. Ptr (Fay a) -> Ptr (a -> Fay b) -> Fay b
>>= Defined b -> Fay (Defined b)
forall a. a -> Fay a
return (Defined b -> Fay (Defined b))
-> (Maybe b -> Defined b) -> Ptr (Maybe b -> Fay (Defined b))
forall t1 t t2. (t1 -> t) -> (t2 -> t1) -> t2 -> t
. Maybe b -> Defined b
forall a. Maybe a -> Defined a
toDefined

mutMapMaybeMI :: (a -> Fay (Defined b)) -> MutMap a -> MutMap b
mutMapMaybeMI :: (a -> Fay (Defined b)) -> MutMap a -> MutMap b
mutMapMaybeMI = [Char] -> (a -> Fay (Defined b)) -> MutMap a -> MutMap b
forall s a. IsString s => s -> a
ffi [Char]
"function () { var r = {}; for(var key in %2){ r[key] = %1(%2[key]); } return r;}()"

-- Mutation

mutInsert :: Text -> a -> MutMap a -> Fay ()
mutInsert :: Text -> a -> MutMap a -> Fay ()
mutInsert = Salted -> a -> MutMap a -> Fay ()
forall a. Salted -> a -> MutMap a -> Fay ()
mutInsertI (Salted -> a -> MutMap a -> Fay ())
-> (Text -> Salted) -> Text -> a -> MutMap a -> Fay ()
forall t1 t t2. (t1 -> t) -> (t2 -> t1) -> t2 -> t
. Text -> Salted
addSalt

mutInsertI :: Salted -> a -> MutMap a -> Fay ()
mutInsertI :: Salted -> a -> MutMap a -> Fay ()
mutInsertI = [Char] -> Salted -> a -> MutMap a -> Fay ()
forall s a. IsString s => s -> a
ffi [Char]
"%3[%1] = %2"

mutDelete :: Text -> MutMap a -> Fay ()
mutDelete :: Text -> MutMap a -> Fay ()
mutDelete = Salted -> MutMap a -> Fay ()
forall a. Salted -> MutMap a -> Fay ()
mutDeleteI (Salted -> MutMap a -> Fay ())
-> (Text -> Salted) -> Text -> MutMap a -> Fay ()
forall t1 t t2. (t1 -> t) -> (t2 -> t1) -> t2 -> t
. Text -> Salted
addSalt

mutDeleteI :: Salted -> MutMap a -> Fay ()
mutDeleteI :: Salted -> MutMap a -> Fay ()
mutDeleteI = [Char] -> Salted -> MutMap a -> Fay ()
forall s a. IsString s => s -> a
ffi [Char]
"delete %2[%1]"

mutClear :: MutMap a -> Fay ()
mutClear :: MutMap a -> Fay ()
mutClear = [Char] -> MutMap a -> Fay ()
forall s a. IsString s => s -> a
ffi [Char]
"function() { for (var k in %1) { delete %1[k]; } }()"

{- NOTE: I put out the effort to write these, but they are untested and ended
   up being unnecessary..

-- Reinserts everything into an object, in order to force serialization, using
-- the still-salted keys.  'Nothing' indicates a removal.
mutToObject :: (a -> Fay (Maybe (Automatic b))) -> MutMap a -> Fay Object
mutToObject f m = do
  obj <- objNew
  mutAssocsI m >>= mapM (\(KeyValI k v) -> do
      mv <- f v
      whenJust mv $ \v' -> objInsert (unsafeCoerce k) v' obj
    )
  return obj

objectToMut :: (Automatic b -> Fay (Maybe a)) -> Object -> Fay (MutMap a)
objectToMut f obj = do
  let obj' = unsafeCoerce obj
  m <- mutEmpty
  mutAssocsI obj' >>= mapM (\(KeyValI k v) -> do
      mv <- f v
      whenJust mv $ \v' -> when (checkSalted k) $ mutInsertI k v' m
    )
  return m
-}