## Description This PR completes the MVC-inspired refactoring by moving the event system from the engine into the reducer. The engine package is now removed entirely, as the reducer handles both reduction logic and lifecycle events. - Add `pkg/reducer/events.go` with `StartEvent`, `StepEvent`, and `StopEvent`. - Extend `Reducer` interface to embed `Emitter[Event]` and add `Expression()` method. - Update `NormalOrderReducer` to embed `BaseEmitter` and emit lifecycle events during reduction. - Update all plugins to attach to `Reducer` instead of `Engine`. - Remove `internal/engine` package entirely. - Add `Off()` method to `BaseEmitter` to complete the `Emitter` interface. - Fix `Emitter.On` signature to use generic type `E` instead of `string`. ### Decisions - The `Reducer` interface now combines reduction logic with event emission, making it the single orchestration point. - Plugins attach directly to the reducer, simplifying the architecture. - The `Expression()` method on `Reducer` provides access to current state for plugins. ## Benefits - Simpler architecture with one fewer abstraction layer. - Plugins are now mode-agnostic - they work with any `Reducer` implementation. - Cleaner separation: reducers handle reduction, plugins observe via events. - Easier to add new evaluation modes - just implement `Reducer` with embedded emitter. ## Checklist - [x] Code follows conventional commit format. - [x] Branch follows naming convention (`<type>/<description>`). - [x] Tests pass (if applicable). - [ ] Documentation updated (if applicable). Reviewed-on: #32 Co-authored-by: M.V. Hutz <git@maximhutz.me> Co-committed-by: M.V. Hutz <git@maximhutz.me>
47 lines
943 B
Go
47 lines
943 B
Go
package emitter
|
|
|
|
import "git.maximhutz.com/max/lambda/pkg/set"
|
|
|
|
type Emitter[E comparable] interface {
|
|
On(E, func()) Listener[E]
|
|
Off(Listener[E])
|
|
Emit(E)
|
|
}
|
|
|
|
type BaseEmitter[E comparable] struct {
|
|
listeners map[E]*set.Set[Listener[E]]
|
|
}
|
|
|
|
func (e *BaseEmitter[E]) On(kind E, fn func()) Listener[E] {
|
|
if e.listeners[kind] == nil {
|
|
e.listeners[kind] = set.New[Listener[E]]()
|
|
}
|
|
|
|
listener := &BaseListener[E]{kind, fn}
|
|
e.listeners[kind].Add(listener)
|
|
return listener
|
|
}
|
|
|
|
func (e *BaseEmitter[E]) Off(listener Listener[E]) {
|
|
kind := listener.Kind()
|
|
if e.listeners[kind] != nil {
|
|
e.listeners[kind].Remove(listener)
|
|
}
|
|
}
|
|
|
|
func (e *BaseEmitter[E]) Emit(event E) {
|
|
if e.listeners[event] == nil {
|
|
e.listeners[event] = set.New[Listener[E]]()
|
|
}
|
|
|
|
for listener := range e.listeners[event].Items() {
|
|
listener.Run()
|
|
}
|
|
}
|
|
|
|
func New[E comparable]() *BaseEmitter[E] {
|
|
return &BaseEmitter[E]{
|
|
listeners: map[E]*set.Set[Listener[E]]{},
|
|
}
|
|
}
|