{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
module Data.Patch.DMap where
import Data.Patch.Class
import Data.Patch.IntMap
import Data.Patch.Map
import Data.Dependent.Map (DMap, DSum (..), GCompare (..))
import qualified Data.Dependent.Map as DMap
import Data.Functor.Constant
import Data.Functor.Misc
import qualified Data.IntMap as IntMap
import qualified Data.Map as Map
import Data.Semigroup (Semigroup (..))
import Data.Some (Some)
newtype PatchDMap k v = PatchDMap { unPatchDMap :: DMap k (ComposeMaybe v) }
deriving instance GCompare k => Semigroup (PatchDMap k v)
deriving instance GCompare k => Monoid (PatchDMap k v)
instance GCompare k => Patch (PatchDMap k v) where
type PatchTarget (PatchDMap k v) = DMap k v
apply (PatchDMap diff) old = Just $! insertions `DMap.union` (old `DMap.difference` deletions)
where insertions = DMap.mapMaybeWithKey (const $ getComposeMaybe) diff
deletions = DMap.mapMaybeWithKey (const $ nothingToJust . getComposeMaybe) diff
nothingToJust = \case
Nothing -> Just $ Constant ()
Just _ -> Nothing
mapPatchDMap :: (forall a. v a -> v' a) -> PatchDMap k v -> PatchDMap k v'
mapPatchDMap f (PatchDMap p) = PatchDMap $ DMap.map (ComposeMaybe . fmap f . getComposeMaybe) p
traversePatchDMap :: Applicative f => (forall a. v a -> f (v' a)) -> PatchDMap k v -> f (PatchDMap k v')
traversePatchDMap f = traversePatchDMapWithKey $ const f
traversePatchDMapWithKey :: Applicative m => (forall a. k a -> v a -> m (v' a)) -> PatchDMap k v -> m (PatchDMap k v')
traversePatchDMapWithKey f (PatchDMap p) = PatchDMap <$> DMap.traverseWithKey (\k (ComposeMaybe v) -> ComposeMaybe <$> traverse (f k) v) p
weakenPatchDMapWith :: (forall a. v a -> v') -> PatchDMap k v -> PatchMap (Some k) v'
weakenPatchDMapWith f (PatchDMap p) = PatchMap $ weakenDMapWith (fmap f . getComposeMaybe) p
patchDMapToPatchMapWith :: (v a -> v') -> PatchDMap (Const2 k a) v -> PatchMap k v'
patchDMapToPatchMapWith f (PatchDMap p) = PatchMap $ dmapToMapWith (fmap f . getComposeMaybe) p
const2PatchDMapWith :: forall k v v' a. (v -> v' a) -> PatchMap k v -> PatchDMap (Const2 k a) v'
const2PatchDMapWith f (PatchMap p) = PatchDMap $ DMap.fromDistinctAscList $ g <$> Map.toAscList p
where g :: (k, Maybe v) -> DSum (Const2 k a) (ComposeMaybe v')
g (k, e) = Const2 k :=> ComposeMaybe (f <$> e)
const2IntPatchDMapWith :: forall v f a. (v -> f a) -> PatchIntMap v -> PatchDMap (Const2 IntMap.Key a) f
const2IntPatchDMapWith f (PatchIntMap p) = PatchDMap $ DMap.fromDistinctAscList $ g <$> IntMap.toAscList p
where g :: (IntMap.Key, Maybe v) -> DSum (Const2 IntMap.Key a) (ComposeMaybe f)
g (k, e) = Const2 k :=> ComposeMaybe (f <$> e)
getDeletions :: GCompare k => PatchDMap k v -> DMap k v' -> DMap k v'
getDeletions (PatchDMap p) m = DMap.intersectionWithKey (\_ v _ -> v) m p