{-# LANGUAGE MultiParamTypeClasses, OverloadedStrings, UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Darcs.Patch.Prim.FileUUID.Apply ( hunkEdit, ObjectMap(..) ) where
import Darcs.Prelude
import Control.Monad.Catch ( MonadThrow(throwM) )
import Control.Monad.State( StateT, runStateT, gets, lift, put )
import qualified Data.ByteString as B
import qualified Data.Map as M
import Darcs.Patch.Apply ( Apply(..) )
import Darcs.Patch.ApplyMonad
( ApplyMonad(..), ApplyMonadTrans(..)
, ApplyMonadOperations
)
import Darcs.Patch.Prim.Class ( PrimApply(..) )
import Darcs.Patch.Prim.FileUUID.Core ( Prim(..), Hunk(..), HunkMove(..) )
import Darcs.Patch.Prim.FileUUID.Show
import Darcs.Patch.Prim.FileUUID.ObjectMap
import Darcs.Patch.Repair ( RepairToFL(..) )
import Darcs.Patch.Witnesses.Ordered ( FL(..) )
import Darcs.Util.Printer( text, packedString, ($$), renderString )
instance Apply Prim where
type ApplyState Prim = ObjectMap
apply :: forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
Prim wX wY -> m ()
apply (Manifest UUID
i (L UUID
dirid Name
name)) = UUID -> (DirContent -> Either String DirContent) -> m ()
forall (m :: * -> *).
ApplyMonadObjectMap m =>
UUID -> (DirContent -> Either String DirContent) -> m ()
editDirectory UUID
dirid (Name -> UUID -> UUID -> DirContent -> Either String DirContent
addObject Name
name UUID
i UUID
dirid)
apply (Demanifest UUID
i (L UUID
dirid Name
name)) = UUID -> (DirContent -> Either String DirContent) -> m ()
forall (m :: * -> *).
ApplyMonadObjectMap m =>
UUID -> (DirContent -> Either String DirContent) -> m ()
editDirectory UUID
dirid (Name -> UUID -> UUID -> DirContent -> Either String DirContent
delObject Name
name UUID
i UUID
dirid)
apply (Hunk UUID
i Hunk wX wY
hunk) = UUID -> (FileContent -> Either String FileContent) -> m ()
forall (m :: * -> *).
ApplyMonadObjectMap m =>
UUID -> (FileContent -> Either String FileContent) -> m ()
editFile UUID
i (Hunk wX wY -> FileContent -> Either String FileContent
forall wX wY.
Hunk wX wY -> FileContent -> Either String FileContent
hunkEdit Hunk wX wY
hunk)
apply (HunkMove (HM UUID
fs Int
ls UUID
ft Int
lt FileContent
c)) =
UUID -> (FileContent -> Either String FileContent) -> m ()
forall (m :: * -> *).
ApplyMonadObjectMap m =>
UUID -> (FileContent -> Either String FileContent) -> m ()
editFile UUID
fs (Hunk Any Any -> FileContent -> Either String FileContent
forall wX wY.
Hunk wX wY -> FileContent -> Either String FileContent
hunkEdit (Int -> FileContent -> FileContent -> Hunk Any Any
forall wX wY. Int -> FileContent -> FileContent -> Hunk wX wY
H Int
ls FileContent
c FileContent
B.empty)) m () -> m () -> m ()
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> UUID -> (FileContent -> Either String FileContent) -> m ()
forall (m :: * -> *).
ApplyMonadObjectMap m =>
UUID -> (FileContent -> Either String FileContent) -> m ()
editFile UUID
ft (Hunk Any Any -> FileContent -> Either String FileContent
forall wX wY.
Hunk wX wY -> FileContent -> Either String FileContent
hunkEdit (Int -> FileContent -> FileContent -> Hunk Any Any
forall wX wY. Int -> FileContent -> FileContent -> Hunk wX wY
H Int
lt FileContent
B.empty FileContent
c))
apply Prim wX wY
Identity = () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
instance RepairToFL Prim where
applyAndTryToFixFL :: forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
Prim wX wY -> m (Maybe (String, FL Prim wX wY))
applyAndTryToFixFL Prim wX wY
p = Prim wX wY -> m ()
forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
Prim wX wY -> m ()
forall (p :: * -> * -> *) (m :: * -> *) wX wY.
(Apply p, ApplyMonad (ApplyState p) m) =>
p wX wY -> m ()
apply Prim wX wY
p m ()
-> m (Maybe (String, FL Prim wX wY))
-> m (Maybe (String, FL Prim wX wY))
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Maybe (String, FL Prim wX wY) -> m (Maybe (String, FL Prim wX wY))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (String, FL Prim wX wY)
forall a. Maybe a
Nothing
instance PrimApply Prim where
applyPrimFL :: forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
FL Prim wX wY -> m ()
applyPrimFL FL Prim wX wY
NilFL = () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
applyPrimFL (Prim wX wY
p :>: FL Prim wY wY
ps) = Prim wX wY -> m ()
forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
Prim wX wY -> m ()
forall (p :: * -> * -> *) (m :: * -> *) wX wY.
(Apply p, ApplyMonad (ApplyState p) m) =>
p wX wY -> m ()
apply Prim wX wY
p m () -> m () -> m ()
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> FL Prim wY wY -> m ()
forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
FL Prim wX wY -> m ()
forall (prim :: * -> * -> *) (m :: * -> *) wX wY.
(PrimApply prim, ApplyMonad (ApplyState prim) m) =>
FL prim wX wY -> m ()
applyPrimFL FL Prim wY wY
ps
addObject :: Name -> UUID -> UUID -> DirContent -> Either String DirContent
addObject :: Name -> UUID -> UUID -> DirContent -> Either String DirContent
addObject Name
name UUID
obj UUID
dirid DirContent
dir
| Just UUID
obj' <- Name -> DirContent -> Maybe UUID
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Name
name DirContent
dir =
String -> Either String DirContent
forall a b. a -> Either a b
Left (String -> Either String DirContent)
-> String -> Either String DirContent
forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords
[ String
"##error applying patch: cannot insert"
, (Name, UUID) -> String
forall a. Show a => a -> String
show (Name
name, UUID
obj)
, String
"into directory"
, UUID -> String
forall a. Show a => a -> String
show UUID
dirid
, String
"because another object"
, UUID -> String
forall a. Show a => a -> String
show UUID
obj'
, String
"with that name already exists"
]
| Bool
otherwise = DirContent -> Either String DirContent
forall a b. b -> Either a b
Right (DirContent -> Either String DirContent)
-> DirContent -> Either String DirContent
forall a b. (a -> b) -> a -> b
$ Name -> UUID -> DirContent -> DirContent
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Name
name UUID
obj DirContent
dir
delObject :: Name -> UUID -> UUID -> DirContent -> Either String DirContent
delObject :: Name -> UUID -> UUID -> DirContent -> Either String DirContent
delObject Name
name UUID
obj UUID
dirid DirContent
dir =
case Name -> DirContent -> Maybe UUID
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Name
name DirContent
dir of
Just UUID
obj'
| UUID
obj UUID -> UUID -> Bool
forall a. Eq a => a -> a -> Bool
== UUID
obj' -> DirContent -> Either String DirContent
forall a b. b -> Either a b
Right (DirContent -> Either String DirContent)
-> DirContent -> Either String DirContent
forall a b. (a -> b) -> a -> b
$ Name -> DirContent -> DirContent
forall k a. Ord k => k -> Map k a -> Map k a
M.delete Name
name DirContent
dir
| Bool
otherwise ->
String -> Either String DirContent
forall a b. a -> Either a b
Left (String -> Either String DirContent)
-> String -> Either String DirContent
forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords
[ String
"##error applying patch: cannot remove"
, (Name, UUID) -> String
forall a. Show a => a -> String
show (Name
name, UUID
obj)
, String
"from directory"
, UUID -> String
forall a. Show a => a -> String
show UUID
dirid
, String
"because it contains a different object"
, UUID -> String
forall a. Show a => a -> String
show UUID
obj'
]
Maybe UUID
Nothing ->
String -> Either String DirContent
forall a b. a -> Either a b
Left (String -> Either String DirContent)
-> String -> Either String DirContent
forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords
[ String
"##error applying patch: cannot remove"
, (Name, UUID) -> String
forall a. Show a => a -> String
show (Name
name, UUID
obj)
, String
"from directory"
, UUID -> String
forall a. Show a => a -> String
show UUID
dirid
, String
"because it does not contain any object of that name"
]
hunkEdit :: Hunk wX wY -> FileContent -> Either String FileContent
hunkEdit :: forall wX wY.
Hunk wX wY -> FileContent -> Either String FileContent
hunkEdit h :: Hunk wX wY
h@(H Int
off FileContent
old FileContent
new) FileContent
c
| FileContent
old FileContent -> FileContent -> Bool
`B.isPrefixOf` (Int -> FileContent -> FileContent
B.drop Int
off FileContent
c) =
FileContent -> Either String FileContent
forall a b. b -> Either a b
Right (FileContent -> Either String FileContent)
-> FileContent -> Either String FileContent
forall a b. (a -> b) -> a -> b
$ [FileContent] -> FileContent
B.concat [Int -> FileContent -> FileContent
B.take Int
off FileContent
c, FileContent
new, Int -> FileContent -> FileContent
B.drop (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ FileContent -> Int
B.length FileContent
old) FileContent
c]
| Bool
otherwise =
String -> Either String FileContent
forall a b. a -> Either a b
Left (String -> Either String FileContent)
-> String -> Either String FileContent
forall a b. (a -> b) -> a -> b
$ Doc -> String
renderString (Doc -> String) -> Doc -> String
forall a b. (a -> b) -> a -> b
$
String -> Doc
text String
"##error applying hunk:" Doc -> Doc -> Doc
$$ Maybe UUID -> Hunk wX wY -> Doc
forall wX wY. Maybe UUID -> Hunk wX wY -> Doc
displayHunk Maybe UUID
forall a. Maybe a
Nothing Hunk wX wY
h Doc -> Doc -> Doc
$$ Doc
"##to" Doc -> Doc -> Doc
$$
FileContent -> Doc
packedString FileContent
c
editObject :: MonadThrow m
=> UUID
-> (Maybe (Object m) -> Either String (Object m))
-> (StateT (ObjectMap m) m) ()
editObject :: forall (m :: * -> *).
MonadThrow m =>
UUID
-> (Maybe (Object m) -> Either String (Object m))
-> StateT (ObjectMap m) m ()
editObject UUID
i Maybe (Object m) -> Either String (Object m)
edit = do
UUID -> m (Maybe (Object m))
load <- (ObjectMap m -> UUID -> m (Maybe (Object m)))
-> StateT (ObjectMap m) m (UUID -> m (Maybe (Object m)))
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets ObjectMap m -> UUID -> m (Maybe (Object m))
forall (m :: * -> *). ObjectMap m -> UUID -> m (Maybe (Object m))
getObject
UUID -> Object m -> m (ObjectMap m)
store <- (ObjectMap m -> UUID -> Object m -> m (ObjectMap m))
-> StateT (ObjectMap m) m (UUID -> Object m -> m (ObjectMap m))
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets ObjectMap m -> UUID -> Object m -> m (ObjectMap m)
forall (m :: * -> *).
ObjectMap m -> UUID -> Object m -> m (ObjectMap m)
putObject
Maybe (Object m)
obj <- m (Maybe (Object m)) -> StateT (ObjectMap m) m (Maybe (Object m))
forall (m :: * -> *) a. Monad m => m a -> StateT (ObjectMap m) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Maybe (Object m)) -> StateT (ObjectMap m) m (Maybe (Object m)))
-> m (Maybe (Object m))
-> StateT (ObjectMap m) m (Maybe (Object m))
forall a b. (a -> b) -> a -> b
$ UUID -> m (Maybe (Object m))
load UUID
i
Object m
obj' <- Either String (Object m) -> StateT (ObjectMap m) m (Object m)
forall (m :: * -> *) a. MonadThrow m => Either String a -> m a
liftEither (Either String (Object m) -> StateT (ObjectMap m) m (Object m))
-> Either String (Object m) -> StateT (ObjectMap m) m (Object m)
forall a b. (a -> b) -> a -> b
$ Maybe (Object m) -> Either String (Object m)
edit Maybe (Object m)
obj
ObjectMap m
new <- m (ObjectMap m) -> StateT (ObjectMap m) m (ObjectMap m)
forall (m :: * -> *) a. Monad m => m a -> StateT (ObjectMap m) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (ObjectMap m) -> StateT (ObjectMap m) m (ObjectMap m))
-> m (ObjectMap m) -> StateT (ObjectMap m) m (ObjectMap m)
forall a b. (a -> b) -> a -> b
$ UUID -> Object m -> m (ObjectMap m)
store UUID
i (Object m -> m (ObjectMap m)) -> Object m -> m (ObjectMap m)
forall a b. (a -> b) -> a -> b
$ Object m
obj'
ObjectMap m -> StateT (ObjectMap m) m ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put ObjectMap m
new
class ApplyMonadObjectMap m where
editFile :: UUID -> (FileContent -> Either String FileContent) -> m ()
editDirectory :: UUID -> (DirContent -> Either String DirContent) -> m ()
type instance ApplyMonadOperations ObjectMap = ApplyMonadObjectMap
instance MonadThrow m => ApplyMonad ObjectMap (StateT (ObjectMap m) m) where
readFilePS :: ObjectIdOf ObjectMap -> StateT (ObjectMap m) m FileContent
readFilePS ObjectIdOf ObjectMap
i = do
UUID -> m (Maybe (Object m))
load <- (ObjectMap m -> UUID -> m (Maybe (Object m)))
-> StateT (ObjectMap m) m (UUID -> m (Maybe (Object m)))
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets ObjectMap m -> UUID -> m (Maybe (Object m))
forall (m :: * -> *). ObjectMap m -> UUID -> m (Maybe (Object m))
getObject
Maybe (Object m)
mobj <- m (Maybe (Object m)) -> StateT (ObjectMap m) m (Maybe (Object m))
forall (m :: * -> *) a. Monad m => m a -> StateT (ObjectMap m) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Maybe (Object m)) -> StateT (ObjectMap m) m (Maybe (Object m)))
-> m (Maybe (Object m))
-> StateT (ObjectMap m) m (Maybe (Object m))
forall a b. (a -> b) -> a -> b
$ UUID -> m (Maybe (Object m))
load ObjectIdOf ObjectMap
UUID
i
case Maybe (Object m)
mobj of
Just (Blob m FileContent
readBlob Maybe Hash
_) -> m FileContent -> StateT (ObjectMap m) m FileContent
forall (m :: * -> *) a. Monad m => m a -> StateT (ObjectMap m) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift m FileContent
readBlob
Just Object m
_ -> IOError -> StateT (ObjectMap m) m FileContent
forall e a.
(HasCallStack, Exception e) =>
e -> StateT (ObjectMap m) m a
forall (m :: * -> *) e a.
(MonadThrow m, HasCallStack, Exception e) =>
e -> m a
throwM (IOError -> StateT (ObjectMap m) m FileContent)
-> IOError -> StateT (ObjectMap m) m FileContent
forall a b. (a -> b) -> a -> b
$ String -> IOError
userError (String -> IOError) -> String -> IOError
forall a b. (a -> b) -> a -> b
$ String
"readFilePS " String -> String -> String
forall a. [a] -> [a] -> [a]
++ UUID -> String
forall a. Show a => a -> String
show ObjectIdOf ObjectMap
UUID
i String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": object is not a file"
Maybe (Object m)
Nothing -> IOError -> StateT (ObjectMap m) m FileContent
forall e a.
(HasCallStack, Exception e) =>
e -> StateT (ObjectMap m) m a
forall (m :: * -> *) e a.
(MonadThrow m, HasCallStack, Exception e) =>
e -> m a
throwM (IOError -> StateT (ObjectMap m) m FileContent)
-> IOError -> StateT (ObjectMap m) m FileContent
forall a b. (a -> b) -> a -> b
$ String -> IOError
userError (String -> IOError) -> String -> IOError
forall a b. (a -> b) -> a -> b
$ String
"readFilePS " String -> String -> String
forall a. [a] -> [a] -> [a]
++ UUID -> String
forall a. Show a => a -> String
show ObjectIdOf ObjectMap
UUID
i String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": no such file"
liftEither :: MonadThrow m => Either String a -> m a
liftEither :: forall (m :: * -> *) a. MonadThrow m => Either String a -> m a
liftEither (Left String
e) = IOError -> m a
forall e a. (HasCallStack, Exception e) => e -> m a
forall (m :: * -> *) e a.
(MonadThrow m, HasCallStack, Exception e) =>
e -> m a
throwM (IOError -> m a) -> IOError -> m a
forall a b. (a -> b) -> a -> b
$ String -> IOError
userError String
e
liftEither (Right a
v) = a -> m a
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
v
instance MonadThrow m => ApplyMonadObjectMap (StateT (ObjectMap m) m) where
editFile :: UUID
-> (FileContent -> Either String FileContent)
-> StateT (ObjectMap m) m ()
editFile UUID
i FileContent -> Either String FileContent
edit = UUID
-> (Maybe (Object m) -> Either String (Object m))
-> StateT (ObjectMap m) m ()
forall (m :: * -> *).
MonadThrow m =>
UUID
-> (Maybe (Object m) -> Either String (Object m))
-> StateT (ObjectMap m) m ()
editObject UUID
i Maybe (Object m) -> Either String (Object m)
forall {m :: * -> *}.
MonadThrow m =>
Maybe (Object m) -> Either String (Object m)
edit'
where
edit' :: Maybe (Object m) -> Either String (Object m)
edit' (Just (Blob m FileContent
x Maybe Hash
_)) = Object m -> Either String (Object m)
forall a b. b -> Either a b
Right (Object m -> Either String (Object m))
-> Object m -> Either String (Object m)
forall a b. (a -> b) -> a -> b
$ m FileContent -> Maybe Hash -> Object m
forall (m :: * -> *). m FileContent -> Maybe Hash -> Object m
Blob (Either String FileContent -> m FileContent
forall (m :: * -> *) a. MonadThrow m => Either String a -> m a
liftEither (Either String FileContent -> m FileContent)
-> (FileContent -> Either String FileContent)
-> FileContent
-> m FileContent
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileContent -> Either String FileContent
edit (FileContent -> m FileContent) -> m FileContent -> m FileContent
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m FileContent
x) Maybe Hash
forall a. Maybe a
Nothing
edit' Maybe (Object m)
Nothing = Object m -> Either String (Object m)
forall a b. b -> Either a b
Right (Object m -> Either String (Object m))
-> Object m -> Either String (Object m)
forall a b. (a -> b) -> a -> b
$ m FileContent -> Maybe Hash -> Object m
forall (m :: * -> *). m FileContent -> Maybe Hash -> Object m
Blob (Either String FileContent -> m FileContent
forall (m :: * -> *) a. MonadThrow m => Either String a -> m a
liftEither (Either String FileContent -> m FileContent)
-> Either String FileContent -> m FileContent
forall a b. (a -> b) -> a -> b
$ FileContent -> Either String FileContent
edit FileContent
"") Maybe Hash
forall a. Maybe a
Nothing
edit' (Just (Directory DirContent
_)) =
String -> Either String (Object m)
forall a b. a -> Either a b
Left (String -> Either String (Object m))
-> String -> Either String (Object m)
forall a b. (a -> b) -> a -> b
$ String
"wrong kind of object: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ UUID -> String
forall a. Show a => a -> String
show UUID
i String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" is a directory, not a file"
editDirectory :: UUID
-> (DirContent -> Either String DirContent)
-> StateT (ObjectMap m) m ()
editDirectory UUID
i DirContent -> Either String DirContent
edit = UUID
-> (Maybe (Object m) -> Either String (Object m))
-> StateT (ObjectMap m) m ()
forall (m :: * -> *).
MonadThrow m =>
UUID
-> (Maybe (Object m) -> Either String (Object m))
-> StateT (ObjectMap m) m ()
editObject UUID
i Maybe (Object m) -> Either String (Object m)
forall {m :: * -> *} {m :: * -> *}.
Maybe (Object m) -> Either String (Object m)
edit'
where
edit' :: Maybe (Object m) -> Either String (Object m)
edit' (Just (Directory DirContent
x)) = DirContent -> Object m
forall (m :: * -> *). DirContent -> Object m
Directory (DirContent -> Object m)
-> Either String DirContent -> Either String (Object m)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DirContent -> Either String DirContent
edit DirContent
x
edit' Maybe (Object m)
Nothing = DirContent -> Object m
forall (m :: * -> *). DirContent -> Object m
Directory (DirContent -> Object m)
-> Either String DirContent -> Either String (Object m)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DirContent -> Either String DirContent
edit DirContent
forall k a. Map k a
M.empty
edit' (Just (Blob m FileContent
_ Maybe Hash
_)) =
String -> Either String (Object m)
forall a b. a -> Either a b
Left (String -> Either String (Object m))
-> String -> Either String (Object m)
forall a b. (a -> b) -> a -> b
$ String
"wrong kind of object: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ UUID -> String
forall a. Show a => a -> String
show UUID
i String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" is a file, not a directory"
instance MonadThrow m => ApplyMonadTrans ObjectMap m where
type ApplyMonadOver ObjectMap m = StateT (ObjectMap m) m
runApplyMonad :: forall x.
ApplyMonadOver ObjectMap m x -> ObjectMap m -> m (x, ObjectMap m)
runApplyMonad = StateT (ObjectMap m) m x -> ObjectMap m -> m (x, ObjectMap m)
ApplyMonadOver ObjectMap m x -> ObjectMap m -> m (x, ObjectMap m)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT