packages feed

eventuo11y 0.5.0.0 → 0.6.0.0

raw patch · 10 files changed

+918/−1054 lines, 10 filesdep +general-allocatedep +monad-controldep +mtldep −resourcetdep −safe-exceptionsdep ~basedep ~transformersPVP ok

version bump matches the API change (PVP)

Dependencies added: general-allocate, monad-control, mtl, transformers-base

Dependencies removed: resourcet, safe-exceptions

Dependency ranges changed: base, transformers

API changes (from Hackage documentation)

- Control.Monad.Cleanup: AbortException :: AbortException
- Control.Monad.Cleanup: CleanupFromMask :: m a -> CleanupFromMask m a
- Control.Monad.Cleanup: CleanupNoException :: m a -> CleanupNoException m a
- Control.Monad.Cleanup: class (Monad m) => MonadCleanup m
- Control.Monad.Cleanup: data AbortException
- Control.Monad.Cleanup: generalCleanup :: MonadCleanup m => m a -> (a -> ExitCase b -> m c) -> (a -> m b) -> m (b, c)
- Control.Monad.Cleanup: instance (Control.Monad.Cleanup.MonadCleanup m, GHC.Base.Monoid w) => Control.Monad.Cleanup.MonadCleanup (Control.Monad.Trans.RWS.Lazy.RWST r w s m)
- Control.Monad.Cleanup: instance (Control.Monad.Cleanup.MonadCleanup m, GHC.Base.Monoid w) => Control.Monad.Cleanup.MonadCleanup (Control.Monad.Trans.RWS.Strict.RWST r w s m)
- Control.Monad.Cleanup: instance (Control.Monad.Cleanup.MonadCleanup m, GHC.Base.Monoid w) => Control.Monad.Cleanup.MonadCleanup (Control.Monad.Trans.Writer.Lazy.WriterT w m)
- Control.Monad.Cleanup: instance (Control.Monad.Cleanup.MonadCleanup m, GHC.Base.Monoid w) => Control.Monad.Cleanup.MonadCleanup (Control.Monad.Trans.Writer.Strict.WriterT w m)
- Control.Monad.Cleanup: instance Control.Monad.Catch.MonadMask m => Control.Monad.Cleanup.MonadCleanup (Control.Monad.Cleanup.CleanupFromMask m)
- Control.Monad.Cleanup: instance Control.Monad.Cleanup.MonadCleanup (GHC.ST.ST s)
- Control.Monad.Cleanup: instance Control.Monad.Cleanup.MonadCleanup Data.Functor.Identity.Identity
- Control.Monad.Cleanup: instance Control.Monad.Cleanup.MonadCleanup GHC.Types.IO
- Control.Monad.Cleanup: instance Control.Monad.Cleanup.MonadCleanup m => Control.Monad.Cleanup.MonadCleanup (Control.Monad.Trans.Except.ExceptT e m)
- Control.Monad.Cleanup: instance Control.Monad.Cleanup.MonadCleanup m => Control.Monad.Cleanup.MonadCleanup (Control.Monad.Trans.Identity.IdentityT m)
- Control.Monad.Cleanup: instance Control.Monad.Cleanup.MonadCleanup m => Control.Monad.Cleanup.MonadCleanup (Control.Monad.Trans.Maybe.MaybeT m)
- Control.Monad.Cleanup: instance Control.Monad.Cleanup.MonadCleanup m => Control.Monad.Cleanup.MonadCleanup (Control.Monad.Trans.Reader.ReaderT r m)
- Control.Monad.Cleanup: instance Control.Monad.Cleanup.MonadCleanup m => Control.Monad.Cleanup.MonadCleanup (Control.Monad.Trans.State.Lazy.StateT s m)
- Control.Monad.Cleanup: instance Control.Monad.Cleanup.MonadCleanup m => Control.Monad.Cleanup.MonadCleanup (Control.Monad.Trans.State.Strict.StateT s m)
- Control.Monad.Cleanup: instance GHC.Base.Applicative m => GHC.Base.Applicative (Control.Monad.Cleanup.CleanupFromMask m)
- Control.Monad.Cleanup: instance GHC.Base.Applicative m => GHC.Base.Applicative (Control.Monad.Cleanup.CleanupNoException m)
- Control.Monad.Cleanup: instance GHC.Base.Functor m => GHC.Base.Functor (Control.Monad.Cleanup.CleanupFromMask m)
- Control.Monad.Cleanup: instance GHC.Base.Functor m => GHC.Base.Functor (Control.Monad.Cleanup.CleanupNoException m)
- Control.Monad.Cleanup: instance GHC.Base.Monad m => Control.Monad.Cleanup.MonadCleanup (Control.Monad.Cleanup.CleanupNoException m)
- Control.Monad.Cleanup: instance GHC.Base.Monad m => GHC.Base.Monad (Control.Monad.Cleanup.CleanupFromMask m)
- Control.Monad.Cleanup: instance GHC.Base.Monad m => GHC.Base.Monad (Control.Monad.Cleanup.CleanupNoException m)
- Control.Monad.Cleanup: instance GHC.Exception.Type.Exception Control.Monad.Cleanup.AbortException
- Control.Monad.Cleanup: instance GHC.Show.Show Control.Monad.Cleanup.AbortException
- Control.Monad.Cleanup: newtype CleanupFromMask m a
- Control.Monad.Cleanup: newtype CleanupNoException m a
- Control.Monad.Cleanup: withCleanup :: MonadCleanup m => m a -> (Maybe SomeException -> a -> m b) -> (a -> m c) -> m c
- Observe.Event: acquireEvent :: MonadUnliftIO m => EventBackend m r s -> forall f. s f -> m (Acquire (Event m r s f))
- Observe.Event: acquireSubEvent :: MonadUnliftIO m => Event m r s f -> forall f'. s f' -> m (Acquire (Event m r s f'))
- Observe.Event: causedEventBackend :: Monad m => (forall f'. s f' -> t f') -> Event m r t f -> EventBackend m r s
- Observe.Event: failEvent :: Monad m => Event m r s f -> SomeException -> m ()
- Observe.Event: hoistEventBackend :: (Functor m, Functor n) => (forall x. m x -> n x) -> EventBackend m r s -> EventBackend n r s
- Observe.Event: narrowEventBackend :: Functor m => (forall f. s f -> t f) -> EventBackend m r t -> EventBackend m r s
- Observe.Event: narrowEventBackend' :: Functor m => (forall f. s f -> forall a. (forall g. t g -> (f -> g) -> a) -> a) -> EventBackend m r t -> EventBackend m r s
- Observe.Event: newEvent :: Applicative m => EventBackend m r s -> forall f. s f -> m (Event m r s f)
- Observe.Event: pairEventBackend :: Applicative m => EventBackend m a s -> EventBackend m b s -> EventBackend m (a, b) s
- Observe.Event: subEventBackend :: Monad m => (forall f'. s f' -> t f') -> Event m r t f -> EventBackend m r s
- Observe.Event: unitEventBackend :: Applicative m => EventBackend m () s
- Observe.Event: withEventMask :: forall m r s. MonadMask m => EventBackend m r s -> forall f. s f -> forall a. (Event m r s f -> m a) -> m a
- Observe.Event: withSubEvent :: MonadCleanup m => Event m r s f -> forall f'. s f' -> (Event m r s f' -> m a) -> m a
- Observe.Event: withSubEventMask :: MonadMask m => Event m r s f -> forall f'. s f' -> (Event m r s f' -> m a) -> m a
- Observe.Event.Backend: AlreadySet :: FlagState
- Observe.Event.Backend: EventImpl :: !r -> !f -> m () -> !r -> m () -> !r -> m () -> !m () -> !SomeException -> m () -> EventImpl m r f
- Observe.Event.Backend: NewlySet :: FlagState
- Observe.Event.Backend: OnceFlag :: m FlagState -> OnceFlag m
- Observe.Event.Backend: [addFieldImpl] :: EventImpl m r f -> !f -> m ()
- Observe.Event.Backend: [addParentImpl] :: EventImpl m r f -> !r -> m ()
- Observe.Event.Backend: [addProximateImpl] :: EventImpl m r f -> !r -> m ()
- Observe.Event.Backend: [checkAndSet] :: OnceFlag m -> m FlagState
- Observe.Event.Backend: [failImpl] :: EventImpl m r f -> !SomeException -> m ()
- Observe.Event.Backend: [finalizeImpl] :: EventImpl m r f -> !m ()
- Observe.Event.Backend: [newEventImpl] :: EventBackend m r s -> !forall f. s f -> m (EventImpl m r f)
- Observe.Event.Backend: [newOnceFlag] :: EventBackend m r s -> !m (OnceFlag m)
- Observe.Event.Backend: [referenceImpl] :: EventImpl m r f -> !r
- Observe.Event.Backend: alwaysNewOnceFlag :: Applicative m => OnceFlag m
- Observe.Event.Backend: data EventBackend m r s
- Observe.Event.Backend: data EventImpl m r f
- Observe.Event.Backend: data FlagState
- Observe.Event.Backend: hoistEventImpl :: (forall x. m x -> n x) -> EventImpl m r f -> EventImpl n r f
- Observe.Event.Backend: hoistOnceFlag :: (forall x. f x -> g x) -> OnceFlag f -> OnceFlag g
- Observe.Event.Backend: narrowEventBackend' :: Functor m => (forall f. s f -> forall a. (forall g. t g -> (f -> g) -> a) -> a) -> EventBackend m r t -> EventBackend m r s
- Observe.Event.Backend: newOnceFlagMVar :: PrimMonad m => m (OnceFlag m)
- Observe.Event.Backend: newtype OnceFlag m
- Observe.Event.Backend: runOnce :: Monad m => OnceFlag m -> m () -> m ()
- Observe.Event.BackendModification: [SetAncestor] :: forall r. r -> EventBackendModifier r r
- Observe.Event.BackendModification: [SetInitialCause] :: forall r. r -> EventBackendModifier r r
- Observe.Event.BackendModification: [Silence] :: forall r. EventBackendModifier r ()
- Observe.Event.BackendModification: data EventBackendModifier r r'
- Observe.Event.BackendModification: data EventBackendModifiers r r'
- Observe.Event.BackendModification: instance Control.Category.Category Observe.Event.BackendModification.EventBackendModifiers
- Observe.Event.BackendModification: modifyEventBackend :: Monad m => EventBackendModifiers r r' -> EventBackend m r s -> EventBackend m r' s
- Observe.Event.BackendModification: setAncestor :: r -> EventBackendModifiers r r
- Observe.Event.BackendModification: setInitialCause :: r -> EventBackendModifiers r r
- Observe.Event.BackendModification: silence :: EventBackendModifiers r ()
- Observe.Event.BackendModification: unmodified :: EventBackendModifiers r r
+ Control.Natural.Control: ControlTransformation :: !forall a. ((forall x. n x -> Compose m st x) -> m a) -> n a -> !forall a. st a -> n a -> ControlTransformation st m n
+ Control.Natural.Control: [restoreState] :: ControlTransformation st m n -> !forall a. st a -> n a
+ Control.Natural.Control: [transWith] :: ControlTransformation st m n -> !forall a. ((forall x. n x -> Compose m st x) -> m a) -> n a
+ Control.Natural.Control: data ControlTransformation st m n
+ Control.Natural.Control: statelessControlTransformation :: forall m n. (Functor m, Applicative n) => (forall a. ((forall x. n x -> m x) -> m a) -> n a) -> StatelessControlTransformation m n
+ Control.Natural.Control: statelessTransWith :: Functor m => StatelessControlTransformation m n -> ((forall x. n x -> m x) -> m a) -> n a
+ Control.Natural.Control: toNatural :: ControlTransformation st m n -> forall x. m x -> n x
+ Control.Natural.Control: type StatelessControlTransformation = ControlTransformation Identity
+ Observe.Event: Parent :: ReferenceType
+ Observe.Event: Proximate :: ReferenceType
+ Observe.Event: Reference :: !ReferenceType -> !r -> Reference r
+ Observe.Event: TransEventMonad :: t (em r s) a -> TransEventMonad t em r s a
+ Observe.Event: [unTransEventMonad] :: TransEventMonad t em r s a -> t (em r s) a
+ Observe.Event: addReference :: Event m r f -> Reference r -> m ()
+ Observe.Event: allocateBackendEvent :: (MonadEvent em, Exceptable e) => forall f. s f -> GeneralAllocate (em r s) e () releaseArg (BackendEvent em r f)
+ Observe.Event: allocateEvent :: (MonadEvent em, Exceptable e) => forall f. s f -> GeneralAllocate (em r s) e () releaseArg (EnvEvent em r s f)
+ Observe.Event: backend :: MonadEvent em => em r s (EnvBackend em r s)
+ Observe.Event: class (forall r s. Monad (em r s), Monad (BackendMonad em)) => MonadEvent em
+ Observe.Event: data EventT m r s a
+ Observe.Event: data Reference r
+ Observe.Event: data ReferenceType
+ Observe.Event: eventLift :: forall m r s. Applicative m => StatelessControlTransformation m (EventT m r s)
+ Observe.Event: hoistBackendEvent :: MonadEvent em => BackendEvent em r f -> EnvEvent em r s f
+ Observe.Event: idInjectSelector :: InjectSelector s s
+ Observe.Event: injectSelector :: (forall f. s f -> t f) -> InjectSelector s t
+ Observe.Event: liftBackendMonad :: MonadEvent em => BackendMonad em a -> em r s a
+ Observe.Event: newBackendEvent :: MonadEvent em => forall f. s f -> em r s (BackendEvent em r f)
+ Observe.Event: newEvent' :: MonadEvent em => forall f. s f -> em r s (EnvEvent em r s f)
+ Observe.Event: newtype TransEventMonad t em r s a
+ Observe.Event: runEventT :: Monad m => EventT m r s a -> EventBackend m r s -> m a
+ Observe.Event: type BackendEvent em = Event (BackendMonad em)
+ Observe.Event: type BackendMonad em :: Type -> Type
+ Observe.Event: type EnvBackend em = EventBackend (BackendMonad em)
+ Observe.Event: type EnvEvent em r s = Event (em r s) r
+ Observe.Event: type InjectSelector s t = forall f. s f -> forall a. (forall g. t g -> (f -> g) -> a) -> a
+ Observe.Event: type MonadWithEvent em r s = (MonadEvent em, PrimMonad (BackendMonad em), MonadWithExceptable (em r s))
+ Observe.Event: withBackendEvent :: (MonadEvent em, MonadWithExceptable (em r s)) => forall f. s f -> (BackendEvent em r f -> em r s a) -> em r s a
+ Observe.Event: withModifiedBackend :: MonadEvent em => (EnvBackend em r s -> EnvBackend em r' s') -> em r' s' a -> em r s a
+ Observe.Event: withNarrowingEvent :: MonadWithEvent em r t => InjectSelector s t -> forall f. t f -> (EnvEvent em r s f -> em r s x) -> em r t x
+ Observe.Event.Backend: Event :: !r -> !f -> m () -> !Reference r -> m () -> !Maybe SomeException -> m () -> Event m r f
+ Observe.Event.Backend: Parent :: ReferenceType
+ Observe.Event.Backend: Proximate :: ReferenceType
+ Observe.Event.Backend: Reference :: !ReferenceType -> !r -> Reference r
+ Observe.Event.Backend: [addField] :: Event m r f -> !f -> m ()
+ Observe.Event.Backend: [addReference] :: Event m r f -> !Reference r -> m ()
+ Observe.Event.Backend: [finalize] :: Event m r f -> !Maybe SomeException -> m ()
+ Observe.Event.Backend: [newEvent] :: EventBackend m r s -> forall f. s f -> m (Event m r f)
+ Observe.Event.Backend: [reference] :: Event m r f -> !r
+ Observe.Event.Backend: data Event m r f
+ Observe.Event.Backend: data Reference r
+ Observe.Event.Backend: data ReferenceType
+ Observe.Event.Backend: hoistEvent :: (forall x. m x -> n x) -> Event m r f -> Event n r f
+ Observe.Event.Backend: idInjectSelector :: InjectSelector s s
+ Observe.Event.Backend: injectSelector :: (forall f. s f -> t f) -> InjectSelector s t
+ Observe.Event.Backend: instance GHC.Classes.Eq Observe.Event.Backend.ReferenceType
+ Observe.Event.Backend: newtype EventBackend m r s
+ Observe.Event.Backend: noopEventBackend :: Applicative m => r -> EventBackend m r s
+ Observe.Event.Backend: setAncestorEventBackend :: PrimMonad m => r -> EventBackend m r s -> EventBackend m r s
+ Observe.Event.Backend: setDefaultReferenceEventBackend :: PrimMonad m => Reference r -> EventBackend m r s -> EventBackend m r s
+ Observe.Event.Backend: setInitialCauseEventBackend :: PrimMonad m => r -> EventBackend m r s -> EventBackend m r s
+ Observe.Event.Backend: setParentEventBackend :: Monad m => r -> EventBackend m r s -> EventBackend m r s
+ Observe.Event.Backend: setProximateEventBackend :: Monad m => r -> EventBackend m r s -> EventBackend m r s
+ Observe.Event.Backend: setReferenceEventBackend :: Monad m => Reference r -> EventBackend m r s -> EventBackend m r s
+ Observe.Event.Backend: type InjectSelector s t = forall f. s f -> forall a. (forall g. t g -> (f -> g) -> a) -> a
+ Observe.Event.Class: -- | The monad of the implicitly carried <a>EventBackend</a>
+ Observe.Event.Class: EventT :: ReaderT (EventBackend m r s) m a -> EventT m r s a
+ Observe.Event.Class: TransEventMonad :: t (em r s) a -> TransEventMonad t em r s a
+ Observe.Event.Class: [unTransEventMonad] :: TransEventMonad t em r s a -> t (em r s) a
+ Observe.Event.Class: backend :: MonadEvent em => em r s (EnvBackend em r s)
+ Observe.Event.Class: class (forall r s. Monad (em r s), Monad (BackendMonad em)) => MonadEvent em where {
+ Observe.Event.Class: eventLift :: forall m r s. Applicative m => StatelessControlTransformation m (EventT m r s)
+ Observe.Event.Class: instance (Observe.Event.Class.MonadEvent em, Control.Monad.Trans.Control.MonadTransControl t, forall (r :: Observe.Event.Class.ReferenceKind) (s :: Observe.Event.Class.SelectorKind). GHC.Base.Monad (t (em r s))) => Observe.Event.Class.MonadEvent (Observe.Event.Class.TransEventMonad t em)
+ Observe.Event.Class: instance Control.Monad.Allocate.MonadAllocate (t (em r s)) => Control.Monad.Allocate.MonadAllocate (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.Allocate.MonadAllocate m => Control.Monad.Allocate.MonadAllocate (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.Base.MonadBase b (t (em r s)) => Control.Monad.Base.MonadBase b (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.Base.MonadBase b m => Control.Monad.Base.MonadBase b (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.Catch.MonadCatch (t (em r s)) => Control.Monad.Catch.MonadCatch (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.Catch.MonadMask (t (em r s)) => Control.Monad.Catch.MonadMask (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.Catch.MonadThrow (t (em r s)) => Control.Monad.Catch.MonadThrow (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.Cont.Class.MonadCont (t (em r s)) => Control.Monad.Cont.Class.MonadCont (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.Cont.Class.MonadCont m => Control.Monad.Cont.Class.MonadCont (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.Error.Class.MonadError e (t (em r s)) => Control.Monad.Error.Class.MonadError e (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.Error.Class.MonadError e m => Control.Monad.Error.Class.MonadError e (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.Fail.MonadFail (t (em r s)) => Control.Monad.Fail.MonadFail (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.Fail.MonadFail m => Control.Monad.Fail.MonadFail (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.Fix.MonadFix (t (em r s)) => Control.Monad.Fix.MonadFix (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.Fix.MonadFix m => Control.Monad.Fix.MonadFix (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.IO.Class.MonadIO (t (em r s)) => Control.Monad.IO.Class.MonadIO (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.IO.Unlift.MonadUnliftIO (t (em r s)) => Control.Monad.IO.Unlift.MonadUnliftIO (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.IO.Unlift.MonadUnliftIO m => Control.Monad.IO.Unlift.MonadUnliftIO (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.Primitive.PrimMonad (t (em r s)) => Control.Monad.Primitive.PrimMonad (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.Primitive.PrimMonad m => Control.Monad.Primitive.PrimMonad (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.Reader.Class.MonadReader r m => Control.Monad.Reader.Class.MonadReader r (Observe.Event.Class.EventT m ref s)
+ Observe.Event.Class: instance Control.Monad.Reader.Class.MonadReader r' (t (em r s)) => Control.Monad.Reader.Class.MonadReader r' (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.State.Class.MonadState s' (t (em r s)) => Control.Monad.State.Class.MonadState s' (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.State.Class.MonadState s' m => Control.Monad.State.Class.MonadState s' (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.Trans.Control.MonadBaseControl b (t (em r s)) => Control.Monad.Trans.Control.MonadBaseControl b (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.Trans.Control.MonadBaseControl b m => Control.Monad.Trans.Control.MonadBaseControl b (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.With.MonadWith (t (em r s)) => Control.Monad.With.MonadWith (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.With.MonadWith m => Control.Monad.With.MonadWith (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.Writer.Class.MonadWriter w (t (em r s)) => Control.Monad.Writer.Class.MonadWriter w (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.Writer.Class.MonadWriter w m => Control.Monad.Writer.Class.MonadWriter w (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Control.Monad.Zip.MonadZip (t (em r s)) => Control.Monad.Zip.MonadZip (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Control.Monad.Zip.MonadZip m => Control.Monad.Zip.MonadZip (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance Data.Functor.Contravariant.Contravariant (t (em r s)) => Data.Functor.Contravariant.Contravariant (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance Data.Functor.Contravariant.Contravariant m => Data.Functor.Contravariant.Contravariant (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance GHC.Base.Alternative (t (em r s)) => GHC.Base.Alternative (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance GHC.Base.Alternative m => GHC.Base.Alternative (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance GHC.Base.Applicative (t (em r s)) => GHC.Base.Applicative (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance GHC.Base.Applicative m => GHC.Base.Applicative (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance GHC.Base.Functor (t (em r s)) => GHC.Base.Functor (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance GHC.Base.Functor m => GHC.Base.Functor (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance GHC.Base.Monad (t (em r s)) => GHC.Base.Monad (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance GHC.Base.Monad m => GHC.Base.Monad (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: instance GHC.Base.Monad m => Observe.Event.Class.MonadEvent (Observe.Event.Class.EventT m)
+ Observe.Event.Class: instance GHC.Base.MonadPlus (t (em r s)) => GHC.Base.MonadPlus (Observe.Event.Class.TransEventMonad t em r s)
+ Observe.Event.Class: instance GHC.Base.MonadPlus m => GHC.Base.MonadPlus (Observe.Event.Class.EventT m r s)
+ Observe.Event.Class: liftBackendMonad :: MonadEvent em => BackendMonad em a -> em r s a
+ Observe.Event.Class: newtype EventT m r s a
+ Observe.Event.Class: newtype TransEventMonad t em r s a
+ Observe.Event.Class: runEventT :: Monad m => EventT m r s a -> EventBackend m r s -> m a
+ Observe.Event.Class: type BackendMonad em :: Type -> Type;
+ Observe.Event.Class: type EnvBackend em = EventBackend (BackendMonad em)
+ Observe.Event.Class: type EventMonadKind = ReferenceKind -> SelectorKind -> FunctorKind
+ Observe.Event.Class: type FunctorKind = Type -> Type
+ Observe.Event.Class: type ReferenceKind = Type
+ Observe.Event.Class: type SelectorKind = Type -> Type
+ Observe.Event.Class: withModifiedBackend :: MonadEvent em => (EnvBackend em r s -> EnvBackend em r' s') -> em r' s' a -> em r s a
+ Observe.Event.Class: }
+ Observe.Event.Explicit: Parent :: ReferenceType
+ Observe.Event.Explicit: Proximate :: ReferenceType
+ Observe.Event.Explicit: Reference :: !ReferenceType -> !r -> Reference r
+ Observe.Event.Explicit: addField :: Event m r f -> f -> m ()
+ Observe.Event.Explicit: addParent :: Event m r f -> r -> m ()
+ Observe.Event.Explicit: addProximate :: Event m r f -> r -> m ()
+ Observe.Event.Explicit: addReference :: Event m r f -> Reference r -> m ()
+ Observe.Event.Explicit: allocateEvent :: (Monad m, Exceptable e) => EventBackend m r s -> forall f. s f -> GeneralAllocate m e () releaseArg (Event m r f)
+ Observe.Event.Explicit: causedEventBackend :: PrimMonad m => InjectSelector s t -> Event m r f -> EventBackend m r t -> EventBackend m r s
+ Observe.Event.Explicit: data Event m r f
+ Observe.Event.Explicit: data EventBackend m r s
+ Observe.Event.Explicit: data Reference r
+ Observe.Event.Explicit: data ReferenceType
+ Observe.Event.Explicit: finalize :: Event m r f -> Maybe SomeException -> m ()
+ Observe.Event.Explicit: hoistEvent :: (forall x. m x -> n x) -> Event m r f -> Event n r f
+ Observe.Event.Explicit: hoistEventBackend :: Functor m => (forall x. m x -> n x) -> EventBackend m r s -> EventBackend n r s
+ Observe.Event.Explicit: idInjectSelector :: InjectSelector s s
+ Observe.Event.Explicit: injectSelector :: (forall f. s f -> t f) -> InjectSelector s t
+ Observe.Event.Explicit: narrowEventBackend :: Functor m => InjectSelector s t -> EventBackend m r t -> EventBackend m r s
+ Observe.Event.Explicit: newEvent :: EventBackend m r s -> forall f. s f -> m (Event m r f)
+ Observe.Event.Explicit: newSubEvent :: Monad m => EventBackend m r s -> Event m r f -> forall f'. s f' -> m (Event m r f')
+ Observe.Event.Explicit: noopEventBackend :: Applicative m => r -> EventBackend m r s
+ Observe.Event.Explicit: pairEventBackend :: Applicative m => EventBackend m a s -> EventBackend m b s -> EventBackend m (a, b) s
+ Observe.Event.Explicit: reference :: Event m r f -> r
+ Observe.Event.Explicit: setAncestorEventBackend :: PrimMonad m => r -> EventBackend m r s -> EventBackend m r s
+ Observe.Event.Explicit: setDefaultReferenceEventBackend :: PrimMonad m => Reference r -> EventBackend m r s -> EventBackend m r s
+ Observe.Event.Explicit: setInitialCauseEventBackend :: PrimMonad m => r -> EventBackend m r s -> EventBackend m r s
+ Observe.Event.Explicit: setParentEventBackend :: Monad m => r -> EventBackend m r s -> EventBackend m r s
+ Observe.Event.Explicit: setProximateEventBackend :: Monad m => r -> EventBackend m r s -> EventBackend m r s
+ Observe.Event.Explicit: setReferenceEventBackend :: Monad m => Reference r -> EventBackend m r s -> EventBackend m r s
+ Observe.Event.Explicit: subEventBackend :: PrimMonad m => InjectSelector s t -> Event m r f -> EventBackend m r t -> EventBackend m r s
+ Observe.Event.Explicit: type InjectSelector s t = forall f. s f -> forall a. (forall g. t g -> (f -> g) -> a) -> a
+ Observe.Event.Explicit: unitEventBackend :: Applicative m => EventBackend m () s
+ Observe.Event.Explicit: withEvent :: MonadWithExceptable m => EventBackend m r s -> forall f. s f -> (Event m r f -> m a) -> m a
+ Observe.Event.Explicit: withSubEvent :: MonadWithExceptable m => EventBackend m r s -> Event m r f -> forall f'. s f' -> (Event m r f' -> m a) -> m a
- Observe.Event: addField :: Event m r s f -> f -> m ()
+ Observe.Event: addField :: Event m r f -> f -> m ()
- Observe.Event: addParent :: Event m r s f -> r -> m ()
+ Observe.Event: addParent :: Event m r f -> r -> m ()
- Observe.Event: addProximate :: Event m r s f -> r -> m ()
+ Observe.Event: addProximate :: Event m r f -> r -> m ()
- Observe.Event: data Event m r s f
+ Observe.Event: data Event m r f
- Observe.Event: finalize :: Monad m => Event m r s f -> m ()
+ Observe.Event: finalize :: Event m r f -> Maybe SomeException -> m ()
- Observe.Event: hoistEvent :: (Functor m, Functor n) => (forall x. m x -> n x) -> Event m r s f -> Event n r s f
+ Observe.Event: hoistEvent :: (forall x. m x -> n x) -> Event m r f -> Event n r f
- Observe.Event: newSubEvent :: Monad m => Event m r s f -> forall f'. s f' -> m (Event m r s f')
+ Observe.Event: newSubEvent :: MonadEvent em => EnvEvent em r s f -> forall f'. s f' -> em r s (EnvEvent em r s f')
- Observe.Event: reference :: Event m r s f -> r
+ Observe.Event: reference :: Event m r f -> r
- Observe.Event: withEvent :: MonadCleanup m => EventBackend m r s -> forall f. s f -> (Event m r s f -> m a) -> m a
+ Observe.Event: withEvent :: MonadWithEvent em r s => forall f. s f -> (EnvEvent em r s f -> em r s a) -> em r s a
- Observe.Event.Backend: EventBackend :: !forall f. s f -> m (EventImpl m r f) -> !m (OnceFlag m) -> EventBackend m r s
+ Observe.Event.Backend: EventBackend :: (forall f. s f -> m (Event m r f)) -> EventBackend m r s
- Observe.Event.Backend: hoistEventBackend :: (Functor m, Functor n) => (forall x. m x -> n x) -> EventBackend m r s -> EventBackend n r s
+ Observe.Event.Backend: hoistEventBackend :: Functor m => (forall x. m x -> n x) -> EventBackend m r s -> EventBackend n r s
- Observe.Event.Backend: narrowEventBackend :: Functor m => (forall f. s f -> t f) -> EventBackend m r t -> EventBackend m r s
+ Observe.Event.Backend: narrowEventBackend :: Functor m => InjectSelector s t -> EventBackend m r t -> EventBackend m r s

Files

CHANGELOG.md view
@@ -1,5 +1,11 @@ # Revision history for eventuo11y +## 0.6.0.0 -- 2022-12-23++- Add `MonadEvent` for implicit backend management+- Simplify `EventBackend` and move to backend-modifying functions instead of `BackendModification`+- Move from `MonadCleanup` to `general-allocate`+ ## 0.5.0.0 -- 2022-10-23  - Add MonadCleanup
− Example.hs
@@ -1,138 +0,0 @@--- Search for comments to find commentary of interest-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE OverloadedLists #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeSynonymInstances #-}--module Main where--import Control.Exception-import Control.Monad-import Data.Aeson-import Data.ByteString.Internal-import Data.Void-import Foreign.C.Error-import Foreign.C.Types-import Foreign.ForeignPtr-import Foreign.Ptr-import GHC.Generics-import Observe.Event-import Observe.Event.DSL-import Observe.Event.Render.JSON-import Observe.Event.Render.JSON.DSL.Compile-import Observe.Event.Render.JSON.Handle-import System.FilePath-import System.IO.Temp-import System.Posix.Files-import System.Posix.IO-import System.Posix.Types---- Pretend this is in a separate module File where--deriving instance Show Errno--deriving instance ToJSON Errno--deriving instance Generic Errno--deriving instance ToJSON CInt--deriving instance Generic CInt--deriving instance ToJSON Fd--deriving instance Generic Fd--deriving instance ToJSON ByteCount--deriving instance Generic ByteCount---- Define our selector type and give it instances to render as JSON-compile $-  SelectorSpec-    "file" -- Creates a type FileSelector-    [ ["open", "file"] -- Creates a constructor OpenFile :: FileSelector OpenField-        ≔ FieldSpec-          "open" -- Creates a type OpenField-          [ "filename" ≔ ''FilePath, -- creates a constructor Filename :: !FilePath -> OpenField-            ["file", "fd"] ≔ ''Fd -- creates a constructor FileFd :: !Fd -> OpenField-          ],-      "write"-        ≔ FieldSpec-          "write"-          [ ["bytes", "asked"] ≔ ''ByteCount,-            ["bytes", "actual"] ≔ ''ByteCount-          ]-    ]---- We take an EventBackend, polymorphic in r, supporting our domain-specific selector type-writeToFile :: EventBackend IO r FileSelector -> FilePath -> ByteString -> IO ()-writeToFile backend path bs = do-  let (fptr, base_off, sz) = toForeignPtr bs-  -- We start an event, selected by OpenFile-  fd <- withEvent backend OpenFile $ \ev -> do-    -- We add a Filename field to our current active event-    addField ev $ Filename path--    fd <- openFd path WriteOnly (Just regularFileMode) defaultFileFlags-    when (fd == -1) $ do-      errno <- getErrno-      -- Throw an exception which we can render as JSON-      throw $ BadOpen path errno--    addField ev $ FileFd fd-    pure fd-  withForeignPtr fptr $ \ptr -> do-    let bcSz = fromIntegral sz-        go :: ByteCount -> IO ()-        go offset = do-          newOffset <- withEvent backend Write $ \ev -> do-            let ct = bcSz - offset-            addField ev $ BytesAsked ct-            written <- fdWriteBuf fd (plusPtr ptr (base_off + fromIntegral offset)) ct-            addField ev $ BytesActual written-            pure $ offset + written-          when (newOffset < bcSz) $-            go newOffset-    go 0-  closeFd fd-  pure ()---- Define a new exception that can be used with simpleJsonStderrBackend-data BadOpen = BadOpen-  { path :: !FilePath,-    errno :: !Errno-  }-  deriving (Show, ToJSON, Generic)---- Our exception is beneath SomeJSONException in the hierarchy-instance Exception BadOpen where-  toException = jsonExceptionToException-  fromException = jsonExceptionFromException---- end module File--compile $-  SelectorSpec-    "main"-    [ ["using", "temp", "dir"] ≔ ''FilePath, -- Creates a constructor UsingTempDir :: MainSelector FilePath-      "writing" ≔ Inject ''FileSelector -- Creates a constructor Writing :: FileSelector x -> MainSelector x-    ]---- Note a different selector type than writeToFile-instrumentedMain :: EventBackend IO r MainSelector -> IO ()-instrumentedMain backend = do-  withEvent backend UsingTempDir $ \ev -> do-    withSystemTempDirectory "example" $ \dir -> do-      addField ev dir-      -- Pass a new EventBackend where all parentless events are made children of our current event-      writeToFile (subEventBackend Writing ev) (dir </> "example.txt") "example"--main :: IO ()-main =-  -- Initialize a backend to write JSON to stderr and use it.-  simpleJsonStderrBackend defaultRenderSelectorJSON >>= instrumentedMain
eventuo11y.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               eventuo11y-version:            0.5.0.0+version:            0.6.0.0 synopsis:           An event-oriented observability library description:   Instrument your Haskell codebase with wide, semantically meaningful events.@@ -32,7 +32,7 @@   See [eventuo11y-json](https://hackage.haskell.org/package/eventuo11y-json) for JSON-based rendering   and backends. -  See [Example.hs](https://github.com/shlevy/eventuo11y/tree/v0.5.0.0/Example.hs) for an example.+  See [Example.hs](https://github.com/shlevy/eventuo11y/tree/v0.6.0.0/Example.hs) for an example.    See [eventuo11y-batteries](https://hackage.haskell.org/package/eventuo11y-batteries) for miscellaneous   framework-specific helpers.@@ -46,8 +46,7 @@ category:           Observability extra-source-files:   CHANGELOG.md-  Example.hs-tested-with:        GHC == { 8.10.7, 9.2.4 }+tested-with:        GHC == { 8.10.7, 9.2.4, 9.4.2 }  source-repository head   type:     git@@ -55,19 +54,22 @@  library   exposed-modules:-    Control.Monad.Cleanup+    Control.Natural.Control     Observe.Event     Observe.Event.Backend-    Observe.Event.BackendModification+    Observe.Event.Class+    Observe.Event.Explicit    build-depends:-    , base             ^>= { 4.14, 4.16 }-    , exceptions       ^>= 0.10-    , primitive        ^>= 0.7-    , resourcet        ^>= { 1.2, 1.3 }-    , safe-exceptions  ^>= 0.1-    , transformers     ^>= 0.5-    , unliftio-core    ^>= 0.2+    , base              ^>= { 4.14, 4.16, 4.17 }+    , exceptions        ^>= { 0.10 }+    , general-allocate  ^>= { 0.2 }+    , primitive         ^>= { 0.7 }+    , transformers      ^>= { 0.5, 0.6 }+    , transformers-base ^>= { 0.4 }+    , monad-control     ^>= { 1.0 }+    , mtl               ^>= { 2.2 }+    , unliftio-core     ^>= { 0.2 }    hs-source-dirs:   src   default-language: Haskell2010
− src/Control/Monad/Cleanup.hs
@@ -1,296 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DerivingStrategies #-}-{-# LANGUAGE DerivingVia #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE InstanceSigs #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TypeApplications #-}---- |--- Description : Monads that can cleanup within a single monaadic scope--- Copyright   : Copyright 2022 Shea Levy.--- License     : Apache-2.0--- Maintainer  : shea@shealevy.com-module Control.Monad.Cleanup where--import Control.Exception.Safe-import Control.Monad.Catch (ExitCase (..))-import Control.Monad.ST-import Control.Monad.Trans.Except (ExceptT (..), runExceptT)-import Control.Monad.Trans.Identity-import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT)-import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS-import qualified Control.Monad.Trans.RWS.Strict as StrictRWS-import Control.Monad.Trans.Reader (ReaderT (..), runReaderT)-import qualified Control.Monad.Trans.State.Lazy as LazyS-import qualified Control.Monad.Trans.State.Strict as StrictS-import qualified Control.Monad.Trans.Writer.Lazy as LazyW-import qualified Control.Monad.Trans.Writer.Strict as StrictW-import Data.Coerce-import Data.Functor.Identity---- | Monads that can cleanup within a single monadic scope.------ 'MonadCleanup's allow for acquiring some resource and--- guaranteeing that it will be released,--- __if computation might continue within that monad__.------ This is very similar to 'MonadMask', with the following differences:------ 1. 'MonadCleanup's may not be able to throw or catch exceptions (no 'MonadCatch'---    superclass) or mask exceptions.--- 2. The guarantee of 'generalCleanup' is not as absolute as 'generalBracket' (though the latter---    always has the @SIGKILL@/power goes out exception). If we can't handle exceptions---    at all in the monad (at least not without @unsafePerformIO@), then sometimes the cleanup---    function won't be called, but only in cases where the entire computation the monad is---    running is going to be aborted.------ This allows 'MonadCleanup' to be used in pure contexts (see 'CleanupNoException') and still--- provide meaningful semantics.-class (Monad m) => MonadCleanup m where-  -- | Acquire some resource, use it, and clean it up.-  ---  -- cleanup is guaranteed to run-  -- __if computation in the surrounding monadic scope might continue__.-  ---  -- Similar to 'generalBracket', see documentation of 'MonadCleanup' for the differences.-  generalCleanup ::-    -- | Acquire some resource-    m a ->-    -- | Release the resource, observing the outcome of the inner action-    (a -> ExitCase b -> m c) ->-    -- | Inner action to perform with the resource-    (a -> m b) ->-    m (b, c)---- | An 'Exception' corresponding to the 'ExitCaseAbort' exit case.-data AbortException = AbortException-  deriving stock (Show)-  deriving anyclass (Exception)---- | Acquire some resource, use it, and clean it up.------ This is to 'bracketWithError' as 'generalCleanup' is to 'generalBracket', see documentation--- of 'generalCleanup' for more details.-withCleanup ::-  (MonadCleanup m) =>-  m a ->-  (Maybe SomeException -> a -> m b) ->-  (a -> m c) ->-  m c-withCleanup acquire cleanup go = fst <$> generalCleanup acquire release go-  where-    release x (ExitCaseSuccess _) = cleanup Nothing x-    release x ExitCaseAbort = cleanup (Just (toException AbortException)) x-    release x (ExitCaseException e) = cleanup (Just e) x---- | A [DerivingVia](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/deriving_via.html) helper for deriving 'MonadCleanup' from 'MonadMask'.-newtype CleanupFromMask m a = CleanupFromMask (m a) deriving newtype (Functor, Applicative, Monad)--instance (MonadMask m) => MonadCleanup (CleanupFromMask m) where-  generalCleanup :: forall a b c. CleanupFromMask m a -> (a -> ExitCase b -> CleanupFromMask m c) -> (a -> CleanupFromMask m b) -> CleanupFromMask m (b, c)-  generalCleanup = coerce $ generalBracket @m @a @b @c--deriving via CleanupFromMask IO instance MonadCleanup IO---- | A [DerivingVia](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/deriving_via.html) for deriving 'MonadCleanup' in a 'Monad' which--- __can't__ handle exceptions.------ If cleanup runs at all, it will run in 'ExitCaseSuccess'------ __Note that the associated 'MonadCleanup' instance is invalid if it is possible to catch exceptions in the monad!__-newtype CleanupNoException m a = CleanupNoException (m a) deriving newtype (Functor, Applicative, Monad)--instance (Monad m) => MonadCleanup (CleanupNoException m) where-  generalCleanup acquire release go = do-    x <- acquire-    res <- go x-    carry <- release x (ExitCaseSuccess res)-    pure (res, carry)--deriving via CleanupNoException (ST s) instance MonadCleanup (ST s)--deriving via CleanupNoException Identity instance MonadCleanup Identity--instance (MonadCleanup m) => MonadCleanup (IdentityT m) where-  generalCleanup acquire release use =-    IdentityT $-      generalCleanup-        (runIdentityT acquire)-        (\resource exitCase -> runIdentityT (release resource exitCase))-        (\resource -> runIdentityT (use resource))--instance MonadCleanup m => MonadCleanup (LazyS.StateT s m) where-  generalCleanup acquire release use = LazyS.StateT $ \s0 -> do-    ((b, _s2), (c, s3)) <--      generalCleanup-        (LazyS.runStateT acquire s0)-        ( \(resource, s1) exitCase -> case exitCase of-            ExitCaseSuccess (b, s2) -> LazyS.runStateT (release resource (ExitCaseSuccess b)) s2-            -- In the two other cases, the base monad overrides @use@'s state-            -- changes and the state reverts to @s1@.-            ExitCaseException e -> LazyS.runStateT (release resource (ExitCaseException e)) s1-            ExitCaseAbort -> LazyS.runStateT (release resource ExitCaseAbort) s1-        )-        (\(resource, s1) -> LazyS.runStateT (use resource) s1)-    return ((b, c), s3)--instance MonadCleanup m => MonadCleanup (StrictS.StateT s m) where-  generalCleanup acquire release use = StrictS.StateT $ \s0 -> do-    ((b, _s2), (c, s3)) <--      generalCleanup-        (StrictS.runStateT acquire s0)-        ( \(resource, s1) exitCase -> case exitCase of-            ExitCaseSuccess (b, s2) -> StrictS.runStateT (release resource (ExitCaseSuccess b)) s2-            -- In the two other cases, the base monad overrides @use@'s state-            -- changes and the state reverts to @s1@.-            ExitCaseException e -> StrictS.runStateT (release resource (ExitCaseException e)) s1-            ExitCaseAbort -> StrictS.runStateT (release resource ExitCaseAbort) s1-        )-        (\(resource, s1) -> StrictS.runStateT (use resource) s1)-    return ((b, c), s3)--instance MonadCleanup m => MonadCleanup (ReaderT r m) where-  generalCleanup acquire release use = ReaderT $ \r ->-    generalCleanup-      (runReaderT acquire r)-      (\resource exitCase -> runReaderT (release resource exitCase) r)-      (\resource -> runReaderT (use resource) r)--instance (MonadCleanup m, Monoid w) => MonadCleanup (StrictW.WriterT w m) where-  generalCleanup acquire release use = StrictW.WriterT $ do-    ((b, _w12), (c, w123)) <--      generalCleanup-        (StrictW.runWriterT acquire)-        ( \(resource, w1) exitCase -> case exitCase of-            ExitCaseSuccess (b, w12) -> do-              (c, w3) <- StrictW.runWriterT (release resource (ExitCaseSuccess b))-              return (c, mappend w12 w3)-            -- In the two other cases, the base monad overrides @use@'s state-            -- changes and the state reverts to @w1@.-            ExitCaseException e -> do-              (c, w3) <- StrictW.runWriterT (release resource (ExitCaseException e))-              return (c, mappend w1 w3)-            ExitCaseAbort -> do-              (c, w3) <- StrictW.runWriterT (release resource ExitCaseAbort)-              return (c, mappend w1 w3)-        )-        ( \(resource, w1) -> do-            (a, w2) <- StrictW.runWriterT (use resource)-            return (a, mappend w1 w2)-        )-    return ((b, c), w123)--instance (MonadCleanup m, Monoid w) => MonadCleanup (LazyW.WriterT w m) where-  generalCleanup acquire release use = LazyW.WriterT $ do-    ((b, _w12), (c, w123)) <--      generalCleanup-        (LazyW.runWriterT acquire)-        ( \(resource, w1) exitCase -> case exitCase of-            ExitCaseSuccess (b, w12) -> do-              (c, w3) <- LazyW.runWriterT (release resource (ExitCaseSuccess b))-              return (c, mappend w12 w3)-            -- In the two other cases, the base monad overrides @use@'s state-            -- changes and the state reverts to @w1@.-            ExitCaseException e -> do-              (c, w3) <- LazyW.runWriterT (release resource (ExitCaseException e))-              return (c, mappend w1 w3)-            ExitCaseAbort -> do-              (c, w3) <- LazyW.runWriterT (release resource ExitCaseAbort)-              return (c, mappend w1 w3)-        )-        ( \(resource, w1) -> do-            (a, w2) <- LazyW.runWriterT (use resource)-            return (a, mappend w1 w2)-        )-    return ((b, c), w123)--instance (MonadCleanup m, Monoid w) => MonadCleanup (LazyRWS.RWST r w s m) where-  generalCleanup acquire release use = LazyRWS.RWST $ \r s0 -> do-    ((b, _s2, _w12), (c, s3, w123)) <--      generalCleanup-        (LazyRWS.runRWST acquire r s0)-        ( \(resource, s1, w1) exitCase -> case exitCase of-            ExitCaseSuccess (b, s2, w12) -> do-              (c, s3, w3) <- LazyRWS.runRWST (release resource (ExitCaseSuccess b)) r s2-              return (c, s3, mappend w12 w3)-            -- In the two other cases, the base monad overrides @use@'s state-            -- changes and the state reverts to @s1@ and @w1@.-            ExitCaseException e -> do-              (c, s3, w3) <- LazyRWS.runRWST (release resource (ExitCaseException e)) r s1-              return (c, s3, mappend w1 w3)-            ExitCaseAbort -> do-              (c, s3, w3) <- LazyRWS.runRWST (release resource ExitCaseAbort) r s1-              return (c, s3, mappend w1 w3)-        )-        ( \(resource, s1, w1) -> do-            (a, s2, w2) <- LazyRWS.runRWST (use resource) r s1-            return (a, s2, mappend w1 w2)-        )-    return ((b, c), s3, w123)--instance (MonadCleanup m, Monoid w) => MonadCleanup (StrictRWS.RWST r w s m) where-  generalCleanup acquire release use = StrictRWS.RWST $ \r s0 -> do-    ((b, _s2, _w12), (c, s3, w123)) <--      generalCleanup-        (StrictRWS.runRWST acquire r s0)-        ( \(resource, s1, w1) exitCase -> case exitCase of-            ExitCaseSuccess (b, s2, w12) -> do-              (c, s3, w3) <- StrictRWS.runRWST (release resource (ExitCaseSuccess b)) r s2-              return (c, s3, mappend w12 w3)-            -- In the two other cases, the base monad overrides @use@'s state-            -- changes and the state reverts to @s1@ and @w1@.-            ExitCaseException e -> do-              (c, s3, w3) <- StrictRWS.runRWST (release resource (ExitCaseException e)) r s1-              return (c, s3, mappend w1 w3)-            ExitCaseAbort -> do-              (c, s3, w3) <- StrictRWS.runRWST (release resource ExitCaseAbort) r s1-              return (c, s3, mappend w1 w3)-        )-        ( \(resource, s1, w1) -> do-            (a, s2, w2) <- StrictRWS.runRWST (use resource) r s1-            return (a, s2, mappend w1 w2)-        )-    return ((b, c), s3, w123)--instance MonadCleanup m => MonadCleanup (MaybeT m) where-  generalCleanup acquire release use = MaybeT $ do-    (eb, ec) <--      generalCleanup-        (runMaybeT acquire)-        ( \resourceMay exitCase -> case resourceMay of-            Nothing -> return Nothing -- nothing to release, acquire didn't succeed-            Just resource -> case exitCase of-              ExitCaseSuccess (Just b) -> runMaybeT (release resource (ExitCaseSuccess b))-              ExitCaseException e -> runMaybeT (release resource (ExitCaseException e))-              _ -> runMaybeT (release resource ExitCaseAbort)-        )-        ( \resourceMay -> case resourceMay of-            Nothing -> return Nothing-            Just resource -> runMaybeT (use resource)-        )-    -- The order in which we perform those two 'Maybe' effects doesn't matter,-    -- since the error message is the same regardless.-    return ((,) <$> eb <*> ec)--instance MonadCleanup m => MonadCleanup (ExceptT e m) where-  generalCleanup acquire release use = ExceptT $ do-    (eb, ec) <--      generalCleanup-        (runExceptT acquire)-        ( \eresource exitCase -> case eresource of-            Left e -> return (Left e) -- nothing to release, acquire didn't succeed-            Right resource -> case exitCase of-              ExitCaseSuccess (Right b) -> runExceptT (release resource (ExitCaseSuccess b))-              ExitCaseException e -> runExceptT (release resource (ExitCaseException e))-              _ -> runExceptT (release resource ExitCaseAbort)-        )-        (either (return . Left) (runExceptT . use))-    return $ do-      -- The order in which we perform those two 'Either' effects determines-      -- which error will win if they are both 'Left's. We want the error from-      -- 'release' to win.-      c <- ec-      b <- eb-      return (b, c)
+ src/Control/Natural/Control.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- |+-- Description : Natural transformations that can lift control operations+-- Copyright   : Copyright 2022 Shea Levy.+-- License     : Apache-2.0+-- Maintainer  : shea@shealevy.com+--+-- Natural transformations can lift monadic actions from the source to the+-- target, but something stronger is needed to lift general higher-order control+-- operations like @catch@.+--+-- This module relates to [Control.Natural](https://hackage.haskell.org/package/natural-transformation/docs/Control-Natural.html)+-- in a similar way to how [Control.Monad.Trans.Control](https://hackage.haskell.org/package/monad-control/docs/Control-Monad-Trans-Control.html)+-- relates to "Control.Monad.Trans.Class".+module Control.Natural.Control where++import Data.Coerce+import Data.Functor.Compose+import Data.Functor.Identity++-- | A transformation from @m@ to @n@ that can lift control operations.+--+-- The @st@ functor is needed to track the higher monad's state+-- in the lower monad. See 'StatelessControlTransformation' for the case+-- where no state tracking is needed.+data ControlTransformation st m n = ControlTransformation+  { -- | Lift an action in @m@, defined in a context where @n@ actions+    -- can be lowered into @m@ with state tracking, into @n@.+    transWith :: !(forall a. ((forall x. n x -> Compose m st x) -> m a) -> n a),+    -- | Restore the state captured by 'transWith'+    restoreState :: !(forall a. st a -> n a)+  }++-- | Extract a natural transformation from a 'ControlTransformation'+toNatural :: ControlTransformation st m n -> (forall x. m x -> n x)+toNatural ct mx = transWith ct $ const mx++-- | A transformation from @m@ to @n@ that can lift control operations.+--+-- This type is only appropriate for the case where the higher monad+-- does not have any additional state that must be accounted for when+-- running within the lower monad. For the more general case, see+-- 'ControlTransformation'.+--+-- I'm told this is a right kan extension.+type StatelessControlTransformation = ControlTransformation Identity++-- | Create a 'StatelessControlTransformation'+statelessControlTransformation ::+  forall m n.+  (Functor m, Applicative n) =>+  -- | Lift an action in @m@, defined in a context where @n@+  -- actions can be lowered into @m@, into @n@.+  (forall a. ((forall x. n x -> m x) -> m a) -> n a) ->+  StatelessControlTransformation m n+statelessControlTransformation transWith' = ControlTransformation {..}+  where+    transWith :: forall a. ((forall x. n x -> Compose m Identity x) -> m a) -> n a+    transWith useRunInM = transWith' $ \runInM -> useRunInM (Compose . fmap Identity . runInM)+    restoreState :: forall a. Identity a -> n a+    restoreState = pure . coerce++-- | Lift an action in @m@, defined in a context where @n@+-- actions can be lowered into @m@, into @n@.+statelessTransWith ::+  (Functor m) =>+  StatelessControlTransformation m n ->+  (((forall x. n x -> m x) -> m a) -> n a)+statelessTransWith (ControlTransformation {..}) useRunInM = transWith $ \runInM -> useRunInM (fmap runIdentity . getCompose . runInM)
src/Observe/Event.hs view
@@ -1,10 +1,21 @@ {-# LANGUAGE ApplicativeDo #-}-{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE QuantifiedConstraints #-} {-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE StandaloneKindSignatures #-} {-# LANGUAGE TypeApplications #-}-{-# LANGUAGE CPP #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE UndecidableInstances #-}+ -- | -- Description : Core interface for instrumentation with eventuo11y -- Copyright   : Copyright 2022 Shea Levy.@@ -29,371 +40,232 @@ -- be both milestone markers ("we got this far in the process") or more detailed -- instrumentation ("we've processed N records"). They are intended to be of a -- domain-specific type per unit of functionality within an instrumented codebase--- (but see t'Observe.Event.Dynamic.DynamicField' for a generic option).+-- (but see [DynamicField](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicField) for a generic option). -- -- Instrumentation then centers around 'Event's, populated using the -- <#g:eventmanip event manipulation functions>. 'Event's are initialized--- with 'EventBackend's, typically via the--- <#g:resourcesafe resource-safe event allocation functions>.+-- with 'MonadEvent' functions, typically via the+-- <#g:resourcesafe resource-safe event allocation functions>. For an+-- explicit alternative to 'MonadEvent', see "Observe.Event.Explicit". -- -- Depending on which 'EventBackend's may end up consuming the 'Event's, -- instrumentors will also need to define renderers for their selectors -- and fields. For example, they may need to implement values of types---  t'Observe.Event.Render.JSON.RenderSelectorJSON' and---  t'Observe.Event.Render.JSON.RenderFieldJSON' to use JSON rendering 'EventBackend's.+-- [RenderSelectorJSON](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Render-JSON.html#t:RenderSelectorJSON)+-- to use JSON rendering 'EventBackend's. module Observe.Event   ( Event,     hoistEvent,      -- * Event manipulation #eventmanip#-    reference,     addField,-    addParent,-    addProximate,+    reference,+    Explicit.addParent,+    Explicit.addProximate,+    addReference,+    Reference (..),+    ReferenceType (..), -    -- * Resource-safe event allocation #resourcesafe#+    -- * MonadEvent+    MonadEvent,+    EnvEvent,++    -- ** Resource-safe event allocation #resourcesafe#     withEvent,-    withSubEvent,+    withNarrowingEvent,+    InjectSelector,+    injectSelector,+    idInjectSelector,+    MonadWithEvent,+    allocateEvent, -    -- ** MonadMask variants-    withEventMask,-    withSubEventMask,+    -- ** EventT+    EventT,+    runEventT,+    eventLift, -    -- ** Acquire/MonadResource variants-    acquireEvent,-    acquireSubEvent,+    -- ** TransEventMonad+    TransEventMonad (..), -    -- * 'EventBackend's+    -- ** Primitives+    BackendMonad,+    EnvBackend,     EventBackend,-    subEventBackend,-    causedEventBackend,-    unitEventBackend,-    pairEventBackend,-    hoistEventBackend,-    narrowEventBackend,-    narrowEventBackend',+    liftBackendMonad,+    backend,+    withModifiedBackend,      -- * Primitive 'Event' resource management.      -- | Prefer the [resource-safe event allocation functions](#g:resourcesafe)     -- to these when possible.     finalize,-    failEvent,-    newEvent,+    newEvent',     newSubEvent,++    -- * Backend Events++    -- | 'Event's within the 'BackendMonad' of a 'MonadEvent'+    --+    -- These are low-level primitives that can be used if the+    -- existing higher-level event allocation/backend modification+    -- combinators are insufficient+    BackendEvent,+    hoistBackendEvent,+    allocateBackendEvent,+    withBackendEvent,+    newBackendEvent,   ) where -import Control.Exception.Safe-import Control.Monad.Cleanup-import Control.Monad.IO.Unlift-import Data.Acquire+import Control.Monad.Primitive+import Control.Monad.With+import Data.Exceptable+import Data.GeneralAllocate+import Data.Kind import Observe.Event.Backend-import Observe.Event.BackendModification---- | An instrumentation event.------ 'Event's are the core of the instrumenting user's interface--- to eventuo11y. Typical usage would be to create an 'Event'--- from an 'EventBackend' with 'withEvent', or as a child of--- an another 'Event' with 'withSubEvent', and add fields to--- the 'Event' at appropriate points in your code with--- 'addField'.------ [@m@]: The monad we're instrumenting in.--- [@r@]: The type of event references. See 'reference'.--- [@s@]: The type of event selectors for child events. See 'EventBackend'.--- [@f@]: The type of fields on this event. See 'addField'.-data Event m r s f = Event-  { -- | The 'EventBackend' this 'Event' was generated from.-    backend :: !(EventBackend m r s),-    -- | The underlying 'EventImpl' implementing the event functionality.-    impl :: !(EventImpl m r f),-    -- | A 'OnceFlag' to ensure we only finish ('finalize' or 'failEvent') once.-    finishFlag :: !(OnceFlag m)-  }---- | Hoist an 'Event' along a given natural transformation into a new monad.-hoistEvent :: (Functor m, Functor n) => (forall x. m x -> n x) -> Event m r s f -> Event n r s f-hoistEvent nt Event {..} =-  Event-    { backend = hoistEventBackend nt backend,-      impl = hoistEventImpl nt impl,-      finishFlag = hoistOnceFlag nt finishFlag-    }---- | Obtain a reference to an 'Event'.------ References are used to link 'Event's together, either in--- parent-child relationships with 'addParent' or in--- cause-effect relationships with 'addProximate'.------ References can live past when an event has been 'finalize'd or--- 'failEvent'ed.------ Code being instrumented should always have @r@ as an unconstrained--- type parameter, both because it is an implementation concern for--- 'EventBackend's and because references are backend-specific and it--- would be an error to reference an event in one backend from an event--- in a different backend.-reference :: Event m r s f -> r-reference (Event {..}) = referenceImpl impl---- | Add a field to an 'Event'.------ Fields make up the basic data captured in an event. They should be added--- to an 'Event' as the code progresses through various phases of work, and can--- be both milestone markers ("we got this far in the process") or more detailed--- instrumentation ("we've processed N records").------ They are intended to be of a domain specific type per unit of functionality--- within an instrumented codebase (but see t'Observe.Event.Dynamic.DynamicField'--- for a generic option).-addField ::-  Event m r s f ->-  -- | The field to add to the event.-  f ->-  m ()-addField (Event {..}) = addFieldImpl impl---- | Mark another 'Event' as a parent of this 'Event'.-addParent ::-  Event m r s f ->-  -- | A reference to the parent, obtained via 'reference'.-  r ->-  m ()-addParent (Event {..}) = addParentImpl impl+import Observe.Event.Class+import qualified Observe.Event.Explicit as Explicit --- | Mark another 'Event' as a proximate cause of this 'Event'.-addProximate ::-  Event m r s f ->-  -- | A reference to the proximate cause, obtained via 'reference'.-  r ->-  m ()-addProximate (Event {..}) = addProximateImpl impl+-- | An 'Event' in a 'MonadEvent'+type EnvEvent :: EventMonadKind -> ReferenceKind -> SelectorKind -> Type -> Type+type EnvEvent em r s = Event (em r s) r --- | Mark an 'Event' as finished.+-- | Run an action with a new 'Event', selected by the given selector. ----- In normal usage, this should be automatically called via the use of--- the [resource-safe event allocation functions](#g:resourcesafe).+-- The selector specifies the category of new event we're creating, as well+-- as the type of fields that can be added to it (with 'addField'). ----- This is a no-op if the 'Event' has already been 'finalize'd or--- 'failEvent'ed. As a result, it is likely pointless to call--- 'addField', 'addParent', or 'addProximate' after this call,--- though it still may be reasonable to call 'reference'.-finalize :: (Monad m) => Event m r s f -> m ()-finalize (Event {..}) = runOnce finishFlag $ finalizeImpl impl---- | Mark an 'Event' as having failed due to an 'Exception'.+-- Selectors are intended to be of a domain specific type per unit of+-- functionality within an instrumented codebase, implemented as a GADT+-- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option). ----- In normal usage, this should be automatically called via the use of--- the [resource-safe event allocation functions](#g:resourcesafe).+-- Within the nested action, all new parentless 'Event's will be+-- made children of the new 'Event'. ----- This is a no-op if the 'Event' has already been 'finalize'd or--- 'failEvent'ed. As a result, it is likely pointless to call--- 'addField', 'addParent', or 'addProximate' after this call,--- though it still may be reasonable to call 'reference'.-failEvent :: (Monad m) => Event m r s f -> SomeException -> m ()-failEvent (Event {..}) = runOnce finishFlag . failImpl impl+-- The 'Event' will be 'finalize'd at the end of the nested action.+withEvent ::+  (MonadWithEvent em r s) =>+  forall f.+  s f ->+  (EnvEvent em r s f -> em r s a) ->+  em r s a+withEvent = withNarrowingEvent idInjectSelector --- | Create a new 'Event', selected by the given selector.+-- | Run an action with a new 'Event' , selected by a given selector, with a narrower sub-selector type. -- -- The selector specifies the category of new event we're creating, as well -- as the type of fields that can be added to it (with 'addField'). -- -- Selectors are intended to be of a domain specific type per unit of -- functionality within an instrumented codebase, implemented as a GADT--- (but see t'Observe.Event.Dynamic.DynamicEventSelector' for a generic option).+-- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option). ----- Consider the [resource-safe event allocation functions](#g:resourcesafe) instead--- of calling this directly.-newEvent ::-  (Applicative m) =>-  EventBackend m r s ->+-- Within the nested action, all new parentless 'Event's will be+-- made children of the new 'Event', and all new 'Event's will+-- be selected by the narrower selector type.+--+-- The 'Event' will be 'finalize'd at the end of the nested action.+withNarrowingEvent ::+  (MonadWithEvent em r t) =>+  InjectSelector s t ->   forall f.-  -- | The event selector.-  s f ->-  m (Event m r s f)-newEvent backend@(EventBackend {..}) sel = do-  impl <- newEventImpl sel-  finishFlag <- newOnceFlag-  pure Event {..}+  t f ->+  (EnvEvent em r s f -> em r s x) ->+  em r t x+withNarrowingEvent inj sel go = withBackendEvent sel $ \ev -> do+  let ev' = hoistBackendEvent ev+  withModifiedBackend (narrowEventBackend inj . setAncestorEventBackend (reference ev)) $ go ev' --- | Create a new 'Event' as a child of the given 'Event', selected by the given selector.+-- | A 'MonadEvent' suitable for running the 'withEvent' family of functions+type MonadWithEvent em r s = (MonadEvent em, PrimMonad (BackendMonad em), MonadWithExceptable (em r s))++-- | Allocate a new 'Event', selected by the given selector. -- -- The selector specifies the category of new event we're creating, as well -- as the type of fields that can be added to it (with 'addField'). -- -- Selectors are intended to be of a domain specific type per unit of -- functionality within an instrumented codebase, implemented as a GADT--- (but see t'Observe.Event.Dynamic.DynamicEventSelector' for a generic option).+-- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option). ----- Consider the [resource-safe event allocation functions](#g:resourcesafe) instead--- of calling this directly.-newSubEvent ::-  (Monad m) =>-  -- | The parent event.-  Event m r s f ->-  forall f'.-  -- | The child event selector.-  s f' ->-  m (Event m r s f')-newSubEvent (Event {..}) sel = do-  child <- newEvent backend sel-  addParent child $ referenceImpl impl-  pure child+-- The 'Event' will be automatically 'finalize'd on release.+allocateEvent ::+  (MonadEvent em, Exceptable e) =>+  forall f.+  s f ->+  GeneralAllocate (em r s) e () releaseArg (EnvEvent em r s f)+allocateEvent = fmap hoistBackendEvent . allocateBackendEvent --- | Run an action with a new 'Event', selected by the given selector.+-- | Create a new 'Event', selected by the given selector. -- -- The selector specifies the category of new event we're creating, as well -- as the type of fields that can be added to it (with 'addField'). -- -- Selectors are intended to be of a domain specific type per unit of -- functionality within an instrumented codebase, implemented as a GADT--- (but see t'Observe.Event.Dynamic.DynamicEventSelector' for a generic option).+-- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option). ----- The 'Event' is automatically 'finalize'd (or, if appropriate, 'failEvent'ed)--- at the end of the function it's passed to.-withEvent ::-  (MonadCleanup m) =>-  EventBackend m r s ->-  forall f.-  -- | The event selector.-  s f ->-  (Event m r s f -> m a) ->-  m a-withEvent backend sel go = withCleanup (newEvent backend sel) cleanup go-  where-    cleanup Nothing = finalize-    cleanup (Just e) = flip failEvent e+-- Consider the [resource-safe event allocation functions](#g:resourcesafe) instead+-- of calling this directly.+newEvent' :: (MonadEvent em) => forall f. s f -> em r s (EnvEvent em r s f)+newEvent' = fmap hoistBackendEvent . newBackendEvent --- | Run an action with a new 'Event' as a child of the given 'Event', selected by the given selector.+-- | Create a new 'Event' as a child of the given 'Event', selected by the given selector. -- -- The selector specifies the category of new event we're creating, as well -- as the type of fields that can be added to it (with 'addField'). -- -- Selectors are intended to be of a domain specific type per unit of -- functionality within an instrumented codebase, implemented as a GADT--- (but see t'Observe.Event.Dynamic.DynamicEventSelector' for a generic option).+-- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option). ----- The 'Event' is automatically 'finalize'd (or, if appropriate, 'failEvent'ed)--- at the end of the function it's passed to.-withSubEvent ::-  (MonadCleanup m) =>-  -- | The parent 'Event'.-  Event m r s f ->+-- Consider the [resource-safe event allocation functions](#g:resourcesafe) instead+-- of calling this directly.+newSubEvent ::+  (MonadEvent em) =>+  EnvEvent em r s f ->   forall f'.-  -- | The child event selector.   s f' ->-  (Event m r s f' -> m a) ->-  m a-withSubEvent (Event {..}) sel go = withEvent backend sel $ \child -> do-  addParent child $ referenceImpl impl-  go child+  em r s (EnvEvent em r s f')+newSubEvent ev sel = do+  child <- newEvent' sel+  Explicit.addParent child $ reference ev+  pure child --- TODO Implement in terms of withEvent + CleanupFromMask+-- | An 'Event' in the 'BackendMonad' of a 'MonadEvent'+type BackendEvent :: EventMonadKind -> ReferenceKind -> Type -> Type+type BackendEvent em = Event (BackendMonad em) --- | 'withEvent' in 'MonadMask'-withEventMask ::-  forall m r s.-  (MonadMask m) =>-  EventBackend m r s ->+-- | Bring a 'BackendEvent' into the 'MonadEvent'+hoistBackendEvent :: (MonadEvent em) => BackendEvent em r f -> EnvEvent em r s f+hoistBackendEvent = hoistEvent liftBackendMonad++-- | A 'BackendMonad' variant of 'allocateEvent'.+allocateBackendEvent ::+  (MonadEvent em, Exceptable e) =>   forall f.-  -- | The event selector.   s f ->-  forall a.-  (Event m r s f -> m a) ->-  m a-withEventMask backend sel go = bracketWithError (newEvent backend sel) release go-  where-    release Nothing = finalize-    release (Just e) = flip failEvent e---- TODO implement in terms of withSubEvent + CleanupFromMask---- | 'withSubEvent' in 'MonadMask'-withSubEventMask ::-  (MonadMask m) =>-  -- | The parent 'Event'.-  Event m r s f ->-  forall f'.-  -- | The child event selector.-  s f' ->-  (Event m r s f' -> m a) ->-  m a-withSubEventMask (Event {..}) sel go = withEventMask backend sel $ \child -> do-  addParent child $ referenceImpl impl-  go child+  GeneralAllocate (em r s) e () releaseArg (BackendEvent em r f)+allocateBackendEvent sel = GeneralAllocate $ \_ -> do+  ev <- newBackendEvent sel+  let release (ReleaseFailure e) = liftBackendMonad . finalize ev . Just $ toSomeException e+      release (ReleaseSuccess _) = liftBackendMonad $ finalize ev Nothing+  pure $ GeneralAllocated ev release --- | An 'Acquire' variant of 'withEvent', usable in a t'Control.Monad.Trans.Resource.MonadResource' with 'allocateAcquire'.+-- | Run an action with a new 'BackendEvent'. ----- Prior to @resourcet@ version @1.3.0@, exceptional exit will 'failEvent' with 'AbortException'.-acquireEvent ::-  (MonadUnliftIO m) =>-  EventBackend m r s ->+-- The 'Event' will be 'finalize'd upon completion.+withBackendEvent ::+  (MonadEvent em, MonadWithExceptable (em r s)) =>   forall f.-  -- | The event selector.   s f ->-  m (Acquire (Event m r s f))-acquireEvent backend sel = withRunInIO $ \runInIO ->-  pure $-    mkAcquireType-      (runInIO $ newEvent backend sel)-      (release runInIO)-  where-#if MIN_VERSION_resourcet(1,3,0)-    release runInIO ev (ReleaseExceptionWith e) = runInIO $ failEvent ev e-#else-    release runInIO ev ReleaseException = runInIO . failEvent ev $ toException AbortException-#endif-    release runInIO ev _ = runInIO $ finalize ev---- | An 'Acquire' variant of 'withSubEvent', usable in a t'Control.Monad.Trans.Resource.MonadResource' with 'allocateAcquire'.------ Prior to @resourcet@ version @1.3.0@, exceptional exit will 'failEvent' with 'AbortException'.-acquireSubEvent ::-  (MonadUnliftIO m) =>-  -- | The parent event.-  Event m r s f ->-  forall f'.-  -- | The child event selector.-  s f' ->-  m (Acquire (Event m r s f'))-acquireSubEvent (Event {..}) sel = do-  childAcq <- acquireEvent backend sel-  withRunInIO $ \runInIO -> pure $ do-    child <- childAcq-    liftIO . runInIO . addParent child $ referenceImpl impl-    pure child---- | An 'EventBackend' where every otherwise parentless event will be marked--- as a child of the given 'Event'.-subEventBackend ::-  (Monad m) =>-  -- | Bring selectors from the new backend into the parent event's backend.-  ---  -- Use 'id' here plus 'narrowEventBackend'' if you need a more general mapping-  -- between selector types.-  (forall f'. s f' -> t f') ->-  -- | The parent event.-  Event m r t f ->-  EventBackend m r s-subEventBackend inj Event {..} =-  narrowEventBackend inj $-    modifyEventBackend (setAncestor $ referenceImpl impl) backend+  (BackendEvent em r f -> em r s a) ->+  em r s a+withBackendEvent = generalWith . allocateBackendEvent --- | An 'EventBackend' where every otherwise causeless event will be marked--- as caused by the given 'Event'.-causedEventBackend ::-  (Monad m) =>-  -- | Bring selectors from the new backend into the causing event's backend.-  ---  -- Use 'id' here plus 'narrowEventBackend'' if you need a more general mapping-  -- between selector types.-  (forall f'. s f' -> t f') ->-  -- | The causing event.-  Event m r t f ->-  EventBackend m r s-causedEventBackend inj Event {..} =-  narrowEventBackend inj $-    modifyEventBackend (setInitialCause $ referenceImpl impl) backend+-- | A 'BackendMonad' variant of 'newEvent''+newBackendEvent :: (MonadEvent em) => forall f. s f -> em r s (BackendEvent em r f)+newBackendEvent sel = do+  b <- backend+  liftBackendMonad $ Explicit.newEvent b sel
src/Observe/Event/Backend.hs view
@@ -1,9 +1,8 @@ {-# LANGUAGE ApplicativeDo #-} {-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE LambdaCase #-}-{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-}  -- | -- Description : Interface for implementing EventBackends@@ -13,34 +12,109 @@ -- -- This is the primary module needed to write new 'EventBackend's. module Observe.Event.Backend-  ( EventBackend (..),-    EventImpl (..),+  ( -- * Core interface+    EventBackend (..),+    Event (..),+    Reference (..),+    ReferenceType (..),++    -- * Backend composition     unitEventBackend,     pairEventBackend,+    noopEventBackend,++    -- * Backend transformation     hoistEventBackend,-    hoistEventImpl,+    hoistEvent,+    InjectSelector,+    injectSelector,+    idInjectSelector,     narrowEventBackend,-    narrowEventBackend',--    -- * OnceFlags--    -- | Generic helper to make operations idempotent.-    OnceFlag (..),-    FlagState (..),-    runOnce,-    hoistOnceFlag,-    alwaysNewOnceFlag,-    newOnceFlagMVar,+    setDefaultReferenceEventBackend,+    setAncestorEventBackend,+    setInitialCauseEventBackend,+    setReferenceEventBackend,+    setParentEventBackend,+    setProximateEventBackend,   ) where  import Control.Exception+import Control.Monad import Control.Monad.Primitive import Data.Functor import Data.Primitive.MVar --- | A backend for creating t'Observe.Event.Event's.+-- | An instrumentation event. --+-- 'Event's are the core of the instrumenting user's interface+-- to eventuo11y. Typical usage would be to create an 'Event'+-- using v'Observe.Event.withEvent' and add fields to the 'Event' at appropriate+-- points in your code with 'addField'.+--+-- [@m@]: The monad we're instrumenting in.+-- [@r@]: The type of event references. See 'reference'.+-- [@f@]: The type of fields on this event. See 'addField'.+data Event m r f = Event+  { -- | Obtain a reference to an 'Event'.+    --+    -- References are used to link 'Event's together, via 'addReference'.+    --+    -- References can live past when an event has been 'finalize'd.+    --+    -- Code being instrumented should always have @r@ as an unconstrained+    -- type parameter, both because it is an implementation concern for+    -- 'EventBackend's and because references are backend-specific and it+    -- would be an error to reference an event in one backend from an event+    -- in a different backend.+    reference :: !r,+    -- | Add a field to an 'Event'.+    --+    -- Fields make up the basic data captured in an event. They should be added+    -- to an 'Event' as the code progresses through various phases of work, and can+    -- be both milestone markers ("we got this far in the process") or more detailed+    -- instrumentation ("we've processed N records").+    --+    -- They are intended to be of a domain specific type per unit of functionality+    -- within an instrumented codebase (but see [DynamicField](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicField)+    -- for a generic option).+    addField :: !(f -> m ()),+    -- | Relate another 'Event' to this 'Event' in the specified way+    addReference :: !(Reference r -> m ()),+    -- | Mark an 'Event' as finished, perhaps due to an 'Exception'.+    --+    -- In normal usage, this should be automatically called via the use of+    -- the [resource-safe event allocation functions](Observe-Event.html#g:resourcesafe).+    --+    -- This is a no-op if the 'Event' has already been 'finalize'd.+    -- As a result, it is likely pointless to call+    -- 'addField' or 'addReference' (or v'Observe.Event.addParent' / v'Observe.Event.addProximate')+    -- after this call, though it still may be reasonable to call 'reference'.+    finalize :: !(Maybe SomeException -> m ())+  }++-- | Hoist an 'Event' along a given natural transformation into a new monad.+hoistEvent :: (forall x. m x -> n x) -> Event m r f -> Event n r f+hoistEvent nt ev =+  ev+    { addField = nt . addField ev,+      addReference = nt . addReference ev,+      finalize = nt . finalize ev+    }++-- | Ways in which 'Event's can 'Reference' each other.+data ReferenceType+  = -- | The 'Reference'd 'Event' is a parent of this 'Event'.+    Parent+  | -- | The 'Reference'd 'Event' is a proximate cause of this 'Event'.+    Proximate+  deriving stock (Eq)++-- | A reference to another 'Event'+data Reference r = Reference !ReferenceType !r++-- | A backend for creating t'Event's.+-- -- Different 'EventBackend's will be used to emit instrumentation to -- different systems. Multiple backends can be combined with -- 'Observe.Event.pairEventBackend'.@@ -64,33 +138,31 @@ -- -- Selectors are intended to be of a domain specific type per unit of -- functionality within an instrumented codebase, implemented as a GADT--- (but see t'Observe.Event.Dynamic.DynamicEventSelector' for a generic option).+-- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option). -- -- Implementations must ensure that 'EventBackend's and their underlying t'Observe.Event.Event's -- are safe to use across threads. -- -- [@m@]: The monad we're instrumenting in. -- [@r@]: The type of event references used in this 'EventBackend'. See 'Observe.Event.reference'.--- [@s@]: The type of event selectors.-data EventBackend m r s = EventBackend-  { -- | Create a new 'EventImpl' corresponding to the given selector.-    newEventImpl :: !(forall f. s f -> m (EventImpl m r f)),-    -- | Allocate a new 'OnceFlag' in our monad.-    newOnceFlag :: !(m (OnceFlag m))-  }---- | The internal implementation of an t'Observe.Event.Event'.------ All fields have corresponding [event manipulation functions](Observe-Event.html#g:eventmanip),--- except that 'finalizeImpl' and 'failImpl' can assume that they will only ever be called--- once (i.e., 'EventImpl' implementations do __not__ have to implement locking internally).-data EventImpl m r f = EventImpl-  { referenceImpl :: !r,-    addFieldImpl :: !(f -> m ()),-    addParentImpl :: !(r -> m ()),-    addProximateImpl :: !(r -> m ()),-    finalizeImpl :: !(m ()),-    failImpl :: !(SomeException -> m ())+-- [@s@]: The type of event selectors. See 'newEvent'.+newtype EventBackend m r s = EventBackend+  { -- | Create a new 'Event', selected by the given selector.+    --+    -- The selector specifies the category of new event we're creating, as well+    -- as the type of fields that can be added to it (with 'addField').+    --+    -- Selectors are intended to be of a domain specific type per unit of+    -- functionality within an instrumented codebase, implemented as a GADT+    -- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option).+    --+    -- Consider the [resource-safe event allocation functions](Observe-Event.html#g:resourcesafe) instead+    -- of calling this directly.+    newEvent ::+      forall f.+      -- The event selector.+      s f ->+      m (Event m r f)   }  -- | A no-op 'EventBackend'.@@ -100,20 +172,7 @@ -- -- 'unitEventBackend' is the algebraic unit of 'pairEventBackend'. unitEventBackend :: Applicative m => EventBackend m () s-unitEventBackend =-  EventBackend-    { newEventImpl = \_ ->-        pure $-          EventImpl-            { referenceImpl = (),-              addFieldImpl = const $ pure (),-              addParentImpl = const $ pure (),-              addProximateImpl = const $ pure (),-              finalizeImpl = pure (),-              failImpl = const $ pure ()-            },-      newOnceFlag = pure alwaysNewOnceFlag-    }+unitEventBackend = noopEventBackend ()  -- | An 'EventBackend' which sequentially generates 'Observe.Event.Event's in the two given 'EventBackend's. --@@ -122,143 +181,139 @@ pairEventBackend :: Applicative m => EventBackend m a s -> EventBackend m b s -> EventBackend m (a, b) s pairEventBackend x y =   EventBackend-    { newEventImpl = \sel -> do-        xImpl <- newEventImpl x sel-        yImpl <- newEventImpl y sel+    { newEvent = \sel -> do+        xEv <- newEvent x sel+        yEv <- newEvent y sel         pure $-          EventImpl-            { referenceImpl = (referenceImpl xImpl, referenceImpl yImpl),-              addFieldImpl = \f -> addFieldImpl xImpl f *> addFieldImpl yImpl f,-              addParentImpl = \(px, py) -> addParentImpl xImpl px *> addParentImpl yImpl py,-              addProximateImpl = \(px, py) -> addProximateImpl xImpl px *> addProximateImpl yImpl py,-              finalizeImpl = finalizeImpl xImpl *> finalizeImpl yImpl,-              failImpl = \e -> failImpl xImpl e *> failImpl yImpl e-            },-      newOnceFlag = do-        xOnce <- newOnceFlag x-        yOnce <- newOnceFlag y+          Event+            { reference = (reference xEv, reference yEv),+              addField = \f -> addField xEv f *> addField yEv f,+              addReference = \(Reference ty (rx, ry)) ->+                addReference xEv (Reference ty rx) *> addReference yEv (Reference ty ry),+              finalize = \me -> finalize xEv me *> finalize yEv me+            }+    }++-- | A no-op 'EventBackend' that can be integrated with other backends.+--+-- This can be used to purposefully ignore instrumentation from some call.+--+-- All events will have the given reference, so can be connected to appropriate+-- events in non-no-op backends, but not in a way that can distinguish between+-- different events from the same no-op backend.+noopEventBackend :: Applicative m => r -> EventBackend m r s+noopEventBackend r =+  EventBackend+    { newEvent = \_ ->         pure $-          OnceFlag $ do-            xSet <- checkAndSet xOnce-            ySet <- checkAndSet yOnce-            pure $ case (xSet, ySet) of-              (NewlySet, NewlySet) -> NewlySet-              _ -> AlreadySet+          Event+            { reference = r,+              addField = const $ pure (),+              addReference = const $ pure (),+              finalize = const $ pure ()+            }     }  -- | Hoist an 'EventBackend' along a given natural transformation into a new monad. hoistEventBackend ::-  (Functor m, Functor n) =>-  -- | Natural transformation from @m@ to @n@.+  (Functor m) =>   (forall x. m x -> n x) ->   EventBackend m r s ->   EventBackend n r s hoistEventBackend nt backend =   EventBackend-    { newEventImpl = nt . fmap (hoistEventImpl nt) . newEventImpl backend,-      newOnceFlag = hoistOnceFlag nt <$> (nt $ newOnceFlag backend)+    { newEvent = nt . fmap (hoistEvent nt) . newEvent backend     } --- | Hoist an 'EventImpl' along a given natural transformation into a new monad.-hoistEventImpl :: (forall x. m x -> n x) -> EventImpl m r f -> EventImpl n r f-hoistEventImpl nt (EventImpl {..}) =-  EventImpl-    { referenceImpl,-      addFieldImpl = nt . addFieldImpl,-      addParentImpl = nt . addParentImpl,-      addProximateImpl = nt . addProximateImpl,-      finalizeImpl = nt finalizeImpl,-      failImpl = nt . failImpl-    }+-- | Inject a narrower selector and its fields into a wider selector.+--+-- See 'injectSelector' for a simple way to construct one of these.+type InjectSelector s t = forall f. s f -> forall a. (forall g. t g -> (f -> g) -> a) -> a +-- | Construct an 'InjectSelector' with a straightforward injection from @s@ to @t@+injectSelector :: (forall f. s f -> t f) -> InjectSelector s t+injectSelector inj sel withInjField = withInjField (inj sel) id++-- | The identity 'InjectSelector'+idInjectSelector :: InjectSelector s s+idInjectSelector s go = go s id+ -- | Narrow an 'EventBackend' to a new selector type via a given injection function. -- -- A typical usage, where component A calls component B, would be to have A's selector -- type have a constructor to take any value of B's selector type (and preserve the field) -- and then call 'narrowEventBackend' with that constructor when invoking functions in B.------ See 'narrowEventBackend'' for a more general, if unweildy, variant. narrowEventBackend ::   (Functor m) =>-  -- | Inject a narrow selector into the wider selector type.-  (forall f. s f -> t f) ->+  InjectSelector s t ->   EventBackend m r t ->   EventBackend m r s-narrowEventBackend inj =-  narrowEventBackend'-    (\sel withInjField -> withInjField (inj sel) id)+narrowEventBackend inj backend =+  EventBackend+    { newEvent = \sel -> inj sel \sel' injField ->+        newEvent backend sel' <&> \ev ->+          ev+            { addField = addField ev . injField+            }+    } --- | Narrow an 'EventBackend' to a new selector type via a given injection function.+-- | Transform an 'EventBackend' so all of its 'Event's have a given 'Reference'. ----- See 'narrowEventBackend' for a simpler, if less general, variant.-narrowEventBackend' ::-  (Functor m) =>-  -- | Simultaneously inject a narrow selector into the wider selector type-  -- and the narrow selector's field into the wider selector's field type.-  (forall f. s f -> forall a. (forall g. t g -> (f -> g) -> a) -> a) ->-  EventBackend m r t ->-  EventBackend m r s-narrowEventBackend' inj backend =+-- You likely want 'setDefaultReferenceEventBackend', if your monad supports it.+setReferenceEventBackend :: (Monad m) => Reference r -> EventBackend m r s -> EventBackend m r s+setReferenceEventBackend r backend =   EventBackend-    { newEventImpl = \sel -> inj sel \sel' injField ->-        newEventImpl backend sel' <&> \case-          EventImpl {..} ->-            EventImpl-              { addFieldImpl = addFieldImpl . injField,-                ..-              },-      newOnceFlag = newOnceFlag backend+    { newEvent = \sel -> do+        ev <- newEvent backend sel+        addReference ev r+        pure ev     } --- | The state of a 'OnceFlag'-data FlagState-  = -- | The flag was not set, but is now-    NewlySet-  | -- | The flag was already set-    AlreadySet---- | A flag to ensure only one operation from some class is performed, once.+-- | Transform an 'EventBackend' so all of its 'Event's have a given parent. ----- Typically consumed via 'runOnce'-newtype OnceFlag m = OnceFlag-  { -- | Get the state of the 'OnceFlag', and set the flag.-    ---    -- This operation should be atomic, and ideally would only-    -- return 'NewlySet' once. In monads that don't support it,-    -- at a minimum it must be monotonic (once one caller gets-    -- 'AlreadySet', all callers will).-    checkAndSet :: m FlagState-  }+-- You likely want 'setAncestorEventBackend', if your monad supports it.+setParentEventBackend :: (Monad m) => r -> EventBackend m r s -> EventBackend m r s+setParentEventBackend = setReferenceEventBackend . Reference Parent --- | Run an operation if no other operations using this--- 'OnceFlag' have run.-runOnce :: (Monad m) => OnceFlag m -> m () -> m ()-runOnce f go =-  checkAndSet f >>= \case-    NewlySet -> go-    AlreadySet -> pure ()+-- | Transform an 'EventBackend' so all of its 'Event's have a given proximate cause.+--+-- You likely want 'setInitialCauseEventBackend', if your monad supports it.+setProximateEventBackend :: (Monad m) => r -> EventBackend m r s -> EventBackend m r s+setProximateEventBackend = setReferenceEventBackend . Reference Proximate --- | A 'OnceFlag' using an 'MVar'.-newOnceFlagMVar :: (PrimMonad m) => m (OnceFlag m)-newOnceFlagMVar = do-  flag <- newEmptyMVar-  pure $-    OnceFlag $-      tryPutMVar flag () <&> \case-        False -> AlreadySet-        True -> NewlySet+-- | Transform an 'EventBackend' so all of its 'Event's have a given 'Reference', if they+-- haven't been given a 'Reference' of the same 'ReferenceType' by the time they are 'finalize'd.+--+-- See 'setReferenceEventBackend' if the 'Reference' should be applied unconditionally.+setDefaultReferenceEventBackend :: (PrimMonad m) => Reference r -> EventBackend m r s -> EventBackend m r s+setDefaultReferenceEventBackend ref@(Reference ty _) backend =+  EventBackend+    { newEvent = \sel -> do+        flag <- newEmptyMVar+        ev <- newEvent backend sel+        pure $+          ev+            { addReference = \ref'@(Reference ty' _) -> do+                when (ty' == ty) . void $ tryPutMVar flag ()+                addReference ev ref',+              finalize = \me -> do+                tryPutMVar flag () >>= \case+                  False -> pure ()+                  True -> addReference ev ref+                finalize ev me+            }+    } --- | A 'OnceFlag' which is always 'NewlySet'.+-- | Transform an 'EventBackend' so all of its 'Event's have a given parent, if they+-- are not given another parent by the time they are 'finalize'd. ----- Only safe to use if the operations to be guarded--- by the flag are already idempotent.-alwaysNewOnceFlag :: (Applicative m) => OnceFlag m-alwaysNewOnceFlag = OnceFlag $ pure NewlySet+-- See 'setParentEventBackend' if the parent should be set unconditionally.+setAncestorEventBackend :: (PrimMonad m) => r -> EventBackend m r s -> EventBackend m r s+setAncestorEventBackend = setDefaultReferenceEventBackend . Reference Parent --- | Hoist a 'OnceFlag' along a given natural transformation into a new monad.-hoistOnceFlag ::-  -- | Natural transformation from @f@ to @g@-  (forall x. f x -> g x) ->-  OnceFlag f ->-  OnceFlag g-hoistOnceFlag nt (OnceFlag cs) = OnceFlag (nt cs)+-- | Transform an 'EventBackend' so all of its 'Event's have a given proximate cause,+-- if they are not given another proximate cause by the time they are 'finalize'd.+--+-- See 'setProximateEventBackend' if the proximate cause should be set unconditionally.+setInitialCauseEventBackend :: (PrimMonad m) => r -> EventBackend m r s -> EventBackend m r s+setInitialCauseEventBackend = setDefaultReferenceEventBackend . Reference Proximate
− src/Observe/Event/BackendModification.hs
@@ -1,158 +0,0 @@-{-# LANGUAGE GADTs #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-}---- |--- Description : Domain-specific language for modifying the behavior of EventBackends--- Copyright   : Copyright 2022 Shea Levy.--- License     : Apache-2.0--- Maintainer  : shea@shealevy.com------ A domain-specific language for modifying the behavior of t'Observe.Event.EventBackend's, needed when--- the caller can't specify the t'Observe.Event.EventBackend' to use directly.------ = The instrumented capability problem------ A common approach for polymorphic effect management in Haskell is the "capability pattern",--- where a function polymorphic in some monad @m@ takes as an argument a value also polymorphic--- in @m@ that can be used to run a constrained set of effects in @m@. One example of such a--- "capability" type would be t'Observe.Event.EventBackend', which for example enables running--- 'Observe.Event.newEvent' in whatever @m@ it's instantiated in. These capabilities are often--- themselves implemented in terms of other capabilities, and are ultimately concretely--- instantiated in some base monad (typically `IO`, or perhaps t`Control.Monad.ST.ST` for a pure--- mock) and then @hoist@ed to the application's monadic context (e.g. 'Observe.Event.hoistEventBackend').------ Normally this compose + hoist approach works fine, since any capabilities that are dependencies of the--- the capability we're hoisting are hidden in its closure. But if a capability depends on an `EventBackend`--- for instrumentation, closing over it at creation time causes a problem: at the call-site of the various--- effects enabled by the capability, we have no way to modify the t'Observe.Event.EventBackend' to e.g. be a noop (because--- we don't need the details of this effect's actions to instrument the calling function effectively) or to--- have its t'Observe.Event.Event's descend from some current 'Observe.Event.Event'. Thus, the DSL defined--- in this module: effects which take some polymorphic capability can *also* take an 'EventBackendModifier'--- and the capability can modify its captured t'Observe.Event.EventBackend' with 'modifyEventBackend' accordingly.------ An alternative would be to have each effect in the capability take an t'Observe.Event.EventBackend' at the call site.--- This would foreclose @hoist@ing along an arbitrary natural transformation, since the t'Observe.Event.EventBackend' would--- be in negative position, but constrained @hoist@ing might be possible with @MonadUnliftIO@ or @MonadUnlift@--- or @MonadBaseControl@ if we share a base monad, or if we implemented t'Observe.Event.EventBackend's in a separate base monad--- that appears in the type of our capabilities and ensure it's liftable to both our application monad and the--- capability's base instantiation.-module Observe.Event.BackendModification-  ( EventBackendModifier (..),-    EventBackendModifiers,-    modifyEventBackend,--    -- * Simple EventBackendModifiers-    unmodified,-    silence,-    setAncestor,-    setInitialCause,-  )-where--import Control.Category-import Observe.Event.Backend-import Prelude hiding (id, (.))---- | Modify an t'Observe.Event.EventBackend', chaging its reference type from @r@ to @r'@-data EventBackendModifier r r' where-  -- | Ignore all instrumentation using the t'Observe.Event.EventBackend'-  Silence :: forall r. EventBackendModifier r ()-  -- | Mark every parentless event as the child of a known t'Observe.Event.Event'.-  SetAncestor ::-    forall r.-    -- | A 'Observe.Event.reference' to the parent t'Observe.Event.Event'.-    r ->-    EventBackendModifier r r-  -- | Mark every causeless event as proximately caused by a known t'Observe.Event.Event'.-  SetInitialCause ::-    forall r.-    -- | A 'Observe.Event.reference' to the causing t'Observe.Event.Event'.-    r ->-    EventBackendModifier r r---- | A sequence of 'EventBackendModifier's------ The free 'Category' over 'EventBackendModifier'-data EventBackendModifiers r r' where-  Nil :: forall r. EventBackendModifiers r r-  Cons :: forall r r' r''. EventBackendModifier r' r'' -> EventBackendModifiers r r' -> EventBackendModifiers r r''--instance Category EventBackendModifiers where-  id = Nil-  Nil . f = f-  (Cons hd tl) . f = Cons hd (tl . f)---- | Modify an t'Observe.Event.EventBackend' according to the given 'EventBackendModifiers'.------ This is a right fold, e.g. @modifyEventBackend (a . b . id) backend@ first--- modifies @backend@ with @b@ and then modifies the result with @a@.-modifyEventBackend :: Monad m => EventBackendModifiers r r' -> EventBackend m r s -> EventBackend m r' s-modifyEventBackend Nil backend = backend-modifyEventBackend (Cons Silence _) _ = unitEventBackend-modifyEventBackend (Cons (SetAncestor parent) rest) backend' =-  EventBackend-    { newEventImpl = \sel -> do-        EventImpl {..} <- newEventImpl backend sel-        parentAdded <- newOnceFlag backend-        pure $-          EventImpl-            { addParentImpl = \r -> do-                _ <- checkAndSet parentAdded-                addParentImpl r,-              finalizeImpl = do-                runOnce parentAdded (addParentImpl parent)-                finalizeImpl,-              failImpl = \e -> do-                runOnce parentAdded (addParentImpl parent)-                failImpl e,-              ..-            },-      newOnceFlag = newOnceFlag backend-    }-  where-    backend = modifyEventBackend rest backend'-modifyEventBackend (Cons (SetInitialCause proximate) rest) backend' =-  EventBackend-    { newEventImpl = \sel -> do-        EventImpl {..} <- newEventImpl backend sel-        proximateAdded <- newOnceFlag backend-        pure $-          EventImpl-            { addProximateImpl = \r -> do-                _ <- checkAndSet proximateAdded-                addParentImpl r,-              finalizeImpl = do-                runOnce proximateAdded (addProximateImpl proximate)-                finalizeImpl,-              failImpl = \e -> do-                runOnce proximateAdded (addProximateImpl proximate)-                failImpl e,-              ..-            },-      newOnceFlag = newOnceFlag backend-    }-  where-    backend = modifyEventBackend rest backend'---- | A single-element 'EventBackendModifiers'-singleton :: EventBackendModifier r r' -> EventBackendModifiers r r'-singleton = flip Cons Nil---- | An 'EventBackendModifiers' that does nothing.-unmodified :: EventBackendModifiers r r-unmodified = id---- | An 'EventBackendModifiers' that silences events.-silence :: EventBackendModifiers r ()-silence = singleton Silence---- | An 'EventBackendModifiers' that marks every parentless event as the child--- of a known t'Observe.Event.Event'.-setAncestor :: r -> EventBackendModifiers r r-setAncestor = singleton . SetAncestor---- | An 'EventBackendModifiers' that marks every causeless event as proximately caused--- by a known t'Observe.Event.Event'.-setInitialCause :: r -> EventBackendModifiers r r-setInitialCause = singleton . SetInitialCause
+ src/Observe/Event/Class.hs view
@@ -0,0 +1,248 @@+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE QuantifiedConstraints #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneKindSignatures #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UndecidableInstances #-}++-- |+-- Description : Typeclass for implicit 'EventBackend' passing+-- Copyright   : Copyright 2022 Shea Levy.+-- License     : Apache-2.0+-- Maintainer  : shea@shealevy.com+--+-- Core typeclass for an mtl-style handling of 'EventBackend's.+-- See "Observe.Event.Explicit" for an explicit, function-based+-- interface.+module Observe.Event.Class+  ( MonadEvent (..),+    EnvBackend,+    TransEventMonad (..),++    -- * EventT+    EventT (..),+    runEventT,+    eventLift,++    -- * Kind aliases+    EventMonadKind,+    ReferenceKind,+    SelectorKind,+    FunctorKind,+  )+where++import Control.Applicative+import Control.Monad+import Control.Monad.Allocate+import Control.Monad.Base+import Control.Monad.Catch+import Control.Monad.Cont.Class+import Control.Monad.Error.Class+import Control.Monad.IO.Unlift+import Control.Monad.Primitive+import Control.Monad.Reader+import Control.Monad.State.Class+import Control.Monad.Trans.Control+import Control.Monad.With+import Control.Monad.Writer.Class+import Control.Monad.Zip+import Control.Natural.Control+import Data.Coerce+import Data.Functor+import Data.Functor.Contravariant+import Data.GeneralAllocate+import Data.Kind+import Observe.Event.Backend++-- | Monads suitable for 'Event'-based instrumentation, with implicit 'EventBackend' management.+--+-- See "Observe.Event.Explicit" for 'Event'-based instrumentation with explicit 'EventBackend'+-- passing.+--+-- Note that @em@ is an indexed monad of 'EventMonadKind'.+type MonadEvent :: EventMonadKind -> Constraint+class (forall r s. Monad (em r s), Monad (BackendMonad em)) => MonadEvent em where+  -- | The monad of the implicitly carried 'EventBackend'+  type BackendMonad em :: Type -> Type++  -- |+  liftBackendMonad :: BackendMonad em a -> em r s a++  -- | Access the implicitly carried 'EventBackend'+  backend :: em r s (EnvBackend em r s)++  -- | Run an instrumented action with a modified 'EventBackend'+  withModifiedBackend ::+    -- | Modify the 'EventBackend'+    --+    -- Note that the modification may change+    -- the reference and selector types.+    (EnvBackend em r s -> EnvBackend em r' s') ->+    -- | Action to run with the modified backend available.+    em r' s' a ->+    em r s a++-- | The type of the implicit 'EventBackend' of a 'MonadEvent'+type EnvBackend :: EventMonadKind -> ReferenceKind -> SelectorKind -> Type+type EnvBackend em = EventBackend (BackendMonad em)++-- | Make a monad into a 'MonadEvent'.+newtype EventT m r s a = EventT (ReaderT (EventBackend m r s) m a)+  deriving newtype+    ( Functor,+      Applicative,+      Monad,+      MonadError e,+      MonadState s',+      MonadWriter w,+      MonadFail,+      MonadFix,+      MonadIO,+      MonadZip,+      Contravariant,+      Alternative,+      MonadPlus,+      MonadCont,+      MonadUnliftIO,+      MonadBase b,+      MonadBaseControl b,+      MonadAllocate,+      MonadCatch,+      MonadThrow,+      MonadMask,+      PrimMonad+    )++-- | Run an 'EventT' with an initial 'EventBackend'.+runEventT :: (Monad m) => EventT m r s a -> EventBackend m r s -> m a+runEventT = coerce++-- | Lift @m@ into 'EventT' @m@.+eventLift :: forall m r s. Applicative m => StatelessControlTransformation m (EventT m r s)+eventLift = statelessControlTransformation $ \useRunInM ->+  coerce @(EventBackend m r s -> _) $ \b -> useRunInM $ flip coerce b++instance MonadReader r m => MonadReader r (EventT m ref s) where+  ask = toNatural eventLift ask+  local modR go = statelessTransWith eventLift $ \runInM ->+    local modR (runInM go)+  reader = toNatural eventLift . reader++instance (MonadWith m) => MonadWith (EventT m r s) where+  type WithException (EventT m r s) = WithException m+  stateThreadingGeneralWith ::+    forall a b releaseReturn.+    GeneralAllocate (EventT m r s) (WithException m) releaseReturn b a ->+    (a -> EventT m r s b) ->+    EventT m r s (b, releaseReturn)+  stateThreadingGeneralWith (GeneralAllocate allocA) go = coerce $ \b -> do+    let allocA' :: (forall x. m x -> m x) -> m (GeneralAllocated m (WithException m) releaseReturn b a)+        allocA' restore = do+          let restore' :: forall x. EventT m r s x -> EventT m r s x+              restore' mx = coerce @(EventBackend m r s -> m x) $ restore . coerce @_ @(EventBackend m r s -> _) mx+          GeneralAllocated a releaseA <- coerce (allocA restore') b+          let releaseA' relTy = coerce @(EventT m r s releaseReturn) @(EventBackend m r s -> m releaseReturn) (releaseA relTy) b+          pure $ GeneralAllocated a releaseA'+    stateThreadingGeneralWith (GeneralAllocate allocA') (flip coerce b . go)++instance (Monad m) => MonadEvent (EventT m) where+  type BackendMonad (EventT m) = m+  liftBackendMonad :: forall a r s. m a -> EventT m r s a+  liftBackendMonad = coerce @(EventBackend m r s -> _) . const++  backend :: forall r s. EventT m r s (EventBackend m r s)+  backend = coerce @(EventBackend m r s -> m _) pure++  withModifiedBackend :: forall r s r' s' a. (EventBackend m r s -> EventBackend m r' s') -> EventT m r' s' a -> EventT m r s a+  withModifiedBackend modBackend e'ma =+    let e'ma' :: EventBackend m r' s' -> m a+        e'ma' = coerce e'ma+     in coerce (e'ma' . modBackend)++-- | Apply a 'MonadTrans'former to an 'EventMonadKind' to get a transformed 'EventMonadKind'+--+-- When @t@ is 'MonadTransControl' and @em@ is 'MonadEvent', 'TransEventMonad' @t@ @em@ is+-- 'MonadEvent' and has all of the relevant instances conferred by @t@.+type TransEventMonad :: (FunctorKind -> FunctorKind) -> EventMonadKind -> EventMonadKind+newtype TransEventMonad t em r s a = TransEventMonad {unTransEventMonad :: t (em r s) a}+  deriving newtype+    ( Functor,+      Applicative,+      Monad,+      MonadError e,+      MonadState s',+      MonadWriter w,+      MonadFail,+      MonadFix,+      MonadIO,+      MonadZip,+      Contravariant,+      Alternative,+      MonadPlus,+      MonadCont,+      MonadUnliftIO,+      MonadBase b,+      MonadBaseControl b,+      MonadAllocate,+      MonadCatch,+      MonadThrow,+      MonadMask,+      PrimMonad,+      MonadReader r'+    )++instance MonadWith (t (em r s)) => MonadWith (TransEventMonad t em r s) where+  type WithException (TransEventMonad t em r s) = WithException (t (em r s))+  stateThreadingGeneralWith ::+    forall a b releaseReturn.+    GeneralAllocate (TransEventMonad t em r s) (WithException (t (em r s))) releaseReturn b a ->+    (a -> TransEventMonad t em r s b) ->+    TransEventMonad t em r s (b, releaseReturn)+  stateThreadingGeneralWith (GeneralAllocate allocA) go = coerce $ do+    stateThreadingGeneralWith (GeneralAllocate allocA') $ coerce go+    where+      allocA' :: (forall x. t (em r s) x -> t (em r s) x) -> t (em r s) (GeneralAllocated (t (em r s)) (WithException (t (em r s))) releaseReturn b a)+      allocA' restore =+        coerce (allocA restore') <&> \case+          GeneralAllocated a releaseA -> GeneralAllocated a $ coerce @(GeneralReleaseType (WithException (t (em r s))) b -> TransEventMonad t em r s releaseReturn) releaseA+        where+          restore' :: forall x. TransEventMonad t em r s x -> TransEventMonad t em r s x+          restore' = coerce @(t (em r s) x -> t (em r s) x) restore++instance (MonadEvent em, MonadTransControl t, forall r s. Monad (t (em r s))) => MonadEvent (TransEventMonad t em) where+  type BackendMonad (TransEventMonad t em) = BackendMonad em+  liftBackendMonad :: forall a r s. BackendMonad em a -> TransEventMonad t em r s a+  liftBackendMonad = coerce @(_ -> t (em r s) a) $ lift . liftBackendMonad++  backend :: forall r s. TransEventMonad t em r s (EnvBackend em r s)+  backend = coerce @(t (em r s) _) $ lift backend++  withModifiedBackend :: forall r s r' s' a. (EnvBackend em r s -> EnvBackend em r' s') -> TransEventMonad t em r' s' a -> TransEventMonad t em r s a+  withModifiedBackend modBackend go = coerce @(t (em r s) _) $+    controlT @_ @_ @a $ \runInEm ->+      withModifiedBackend modBackend . runInEm $ coerce @_ @(t (em r' s') a) go++-- | The kind of indexed monads aware of 'Event' instrumentation+--+-- See 'MonadEvent'.+type EventMonadKind = ReferenceKind -> SelectorKind -> FunctorKind++-- | The kind of 'Event' references+type ReferenceKind = Type++-- | The kind of 'Event' selectors+type SelectorKind = Type -> Type++-- | The kind of 'Functor's+type FunctorKind = Type -> Type
+ src/Observe/Event/Explicit.hs view
@@ -0,0 +1,201 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RankNTypes #-}++-- |+-- Description : Instrumentation with explicit 'EventBackend' passing+-- Copyright   : Copyright 2022 Shea Levy.+-- License     : Apache-2.0+-- Maintainer  : shea@shealevy.com+--+-- t'Observe.Event.MonadEvent' and 'Observe.Event.EventT'-based instrumentation+-- implicitly track the underlying 'EventBackend' for you. This module is for those+-- who would rather pass around 'EventBackend's explicitly.+module Observe.Event.Explicit+  ( Event,+    hoistEvent,++    -- * Event manipulation #eventmanip#+    addField,+    reference,+    addParent,+    addProximate,+    addReference,+    Reference (..),+    ReferenceType (..),++    -- * Resource-safe event allocation #resourcesafe#+    allocateEvent,+    withEvent,+    withSubEvent,++    -- * 'EventBackend's+    EventBackend,++    -- ** Backend transformation+    subEventBackend,+    causedEventBackend,+    hoistEventBackend,+    narrowEventBackend,+    InjectSelector,+    injectSelector,+    idInjectSelector,+    setDefaultReferenceEventBackend,+    setAncestorEventBackend,+    setInitialCauseEventBackend,+    setReferenceEventBackend,+    setParentEventBackend,+    setProximateEventBackend,++    -- ** Backend composition+    unitEventBackend,+    pairEventBackend,+    noopEventBackend,++    -- * Primitive 'Event' resource management.++    -- | Prefer the [resource-safe event allocation functions](#g:resourcesafe)+    -- to these when possible.+    finalize,+    newEvent,+    newSubEvent,+  )+where++import Control.Monad.Primitive+import Control.Monad.With+import Data.Exceptable+import Data.GeneralAllocate+import Observe.Event.Backend++-- | Mark another 'Event' as a parent of this 'Event'.+addParent ::+  Event m r f ->+  r ->+  m ()+addParent ev = addReference ev . Reference Parent++-- | Mark another 'Event' as a proximate cause of this 'Event'.+addProximate ::+  Event m r f ->+  r ->+  m ()+addProximate ev = addReference ev . Reference Proximate++-- | Allocate a new 'Event', selected by the given selector.+--+-- The selector specifies the category of new event we're creating, as well+-- as the type of fields that can be added to it (with 'addField').+--+-- Selectors are intended to be of a domain specific type per unit of+-- functionality within an instrumented codebase, implemented as a GADT+-- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option).+--+-- The 'Event' is automatically 'finalize'd on release.+allocateEvent ::+  (Monad m, Exceptable e) =>+  EventBackend m r s ->+  forall f.+  s f ->+  GeneralAllocate m e () releaseArg (Event m r f)+allocateEvent backend sel = GeneralAllocate $ \restore -> do+  ev <- restore $ newEvent backend sel+  let release (ReleaseFailure e) = finalize ev . Just $ toSomeException e+      release (ReleaseSuccess _) = finalize ev Nothing+  pure $ GeneralAllocated ev release++-- | Create a new 'Event' as a child of the given 'Event', selected by the given selector.+--+-- The selector specifies the category of new event we're creating, as well+-- as the type of fields that can be added to it (with 'addField').+--+-- Selectors are intended to be of a domain specific type per unit of+-- functionality within an instrumented codebase, implemented as a GADT+-- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option).+--+-- Consider the [resource-safe event allocation functions](#g:resourcesafe) instead+-- of calling this directly.+newSubEvent ::+  (Monad m) =>+  EventBackend m r s ->+  -- | The parent event.+  Event m r f ->+  forall f'.+  -- | The child event selector.+  s f' ->+  m (Event m r f')+newSubEvent backend ev sel = do+  child <- newEvent backend sel+  addParent child $ reference ev+  pure child++-- | Run an action with a new 'Event', selected by the given selector.+--+-- The selector specifies the category of new event we're creating, as well+-- as the type of fields that can be added to it (with 'addField').+--+-- Selectors are intended to be of a domain specific type per unit of+-- functionality within an instrumented codebase, implemented as a GADT+-- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option).+--+-- The 'Event' is automatically 'finalize'd at the end of the function it's passed to.+withEvent ::+  (MonadWithExceptable m) =>+  EventBackend m r s ->+  forall f.+  -- | The event selector.+  s f ->+  (Event m r f -> m a) ->+  m a+withEvent backend = generalWith . allocateEvent backend++-- | Run an action with a new 'Event' as a child of the given 'Event', selected by the given selector.+--+-- The selector specifies the category of new event we're creating, as well+-- as the type of fields that can be added to it (with 'addField').+--+-- Selectors are intended to be of a domain specific type per unit of+-- functionality within an instrumented codebase, implemented as a GADT+-- (but see [DynamicEventSelector](https://hackage.haskell.org/package/eventuo11y-json/docs/Observe-Event-Dynamic.html#t:DynamicEventSelector) for a generic option).+--+-- The 'Event' is automatically 'finalize'd at the end of the function it's passed to.+withSubEvent ::+  (MonadWithExceptable m) =>+  EventBackend m r s ->+  -- | The parent 'Event'.+  Event m r f ->+  forall f'.+  -- | The child event selector.+  s f' ->+  (Event m r f' -> m a) ->+  m a+withSubEvent backend ev sel go = withEvent backend sel $ \child -> do+  addParent child $ reference ev+  go child++-- | An 'EventBackend' where every otherwise parentless event will be marked+-- as a child of the given 'Event'.+subEventBackend ::+  (PrimMonad m) =>+  -- | Bring selectors from the new backend into the parent event's backend.+  InjectSelector s t ->+  -- | The parent event.+  Event m r f ->+  EventBackend m r t ->+  EventBackend m r s+subEventBackend inj ev =+  narrowEventBackend inj+    . setAncestorEventBackend (reference ev)++-- | An 'EventBackend' where every otherwise causeless event will be marked+-- as caused by the given 'Event'.+causedEventBackend ::+  (PrimMonad m) =>+  -- | Bring selectors from the new backend into the causing event's backend.+  InjectSelector s t ->+  -- | The causing event.+  Event m r f ->+  EventBackend m r t ->+  EventBackend m r s+causedEventBackend inj ev =+  narrowEventBackend inj+    . setInitialCauseEventBackend (reference ev)