diff --git a/module/build.go b/module/build.go new file mode 100644 index 0000000..5a39934 --- /dev/null +++ b/module/build.go @@ -0,0 +1,66 @@ +package module + +import ( + "context" + + "github.com/googollee/go-espresso" +) + +func Build(ctx context.Context, server *espresso.Server, modules []Module) ([]ModuleImplementer, error) { + bctx := newBuildContext(ctx, server) + + for _, m := range modules { + if err := m.build(bctx); err != nil { + return nil, err + } + } + + return bctx.Modules(), nil +} + +type buildContext struct { + context.Context + server *espresso.Server + deps map[moduleName]struct{} + instances map[moduleName]ModuleImplementer + err error +} + +func newBuildContext(ctx context.Context, server *espresso.Server) *buildContext { + return &buildContext{ + Context: ctx, + server: server, + deps: make(map[moduleName]struct{}), + instances: make(map[moduleName]ModuleImplementer), + } +} + +func (c *buildContext) Child() *buildContext { + return &buildContext{ + Context: c.Context, + server: c.server, + deps: make(map[moduleName]struct{}), + instances: c.instances, + } +} + +func (c *buildContext) Value(key any) any { + name, ok := key.(moduleName) + if !ok { + return c.Context.Value(key) + } + + return c.Module(name) +} + +func (c *buildContext) Module(name moduleName) ModuleImplementer { + return c.instances[name] +} + +func (c *buildContext) Modules() []ModuleImplementer { + ret := make([]ModuleImplementer, 0, len(c.instances)) + for _, i := range c.instances { + ret = append(ret, i) + } + return ret +} diff --git a/module/build_context.go b/module/build_context.go deleted file mode 100644 index 00d8c98..0000000 --- a/module/build_context.go +++ /dev/null @@ -1,28 +0,0 @@ -package module - -import ( - "context" - - "github.com/googollee/go-espresso" -) - -type buildContext struct { - context.Context - server *espresso.Server - deps map[moduleName]struct{} - modules map[moduleName]ModuleImplementer - err error -} - -func (c *buildContext) Value(key any) any { - name, ok := key.(moduleName) - if !ok { - return c.Context.Value(key) - } - - return c.modules[name] -} - -func (c *buildContext) module(name moduleName) ModuleImplementer { - return c.modules[name] -} diff --git a/module/module_test.go b/module/module_test.go index f4725be..1551443 100644 --- a/module/module_test.go +++ b/module/module_test.go @@ -1,9 +1,61 @@ package module -import "context" +import ( + "context" + "testing" + + "github.com/googollee/go-espresso" +) + +// - Module1 +// - Module2 +// - Module3 +// - Module5 +// - Module2 +// - Module4 +// - Module5 type fakeModule struct{} func (fakeModule) CheckHealthy(context.Context) error { return nil } -var _ Module = &ModuleType[fakeModule]{} +func buildFake[T ModuleImplementer](context.Context, *espresso.Server) (*T, error) { + var t T + return &t, nil +} + +type Module1 struct{ fakeModule } +type Module2 struct{ fakeModule } +type Module3 struct{ fakeModule } +type Module4 struct{ fakeModule } +type Module5 struct{ fakeModule } + +var ( + build1 = buildFake[Module1] + build2 = buildFake[Module2] + build3 = buildFake[Module3] + build4 = buildFake[Module4] + build5 = buildFake[Module5] +) + +var ( + module1 = NewModule(build1) + module2 = NewModule(build2) + module3 = NewModule(build3) + module4 = NewModule(build4) + module5 = NewModule(build5) +) + +func TestModule(t *testing.T) { + ctx := context.Background() + server := &espresso.Server{} + + modules, err := Build(ctx, server, []Module{module1, module2, module5}) + if err != nil { + t.Fatalf("Build(ctx, server, {module1, module2, module5}) returns error: %v", err) + } + + if got, want := len(modules), 5; got != want { + t.Fatalf("len(modules) = %v, want: %v", got, want) + } +} diff --git a/module/type.go b/module/type.go index a9530a5..74e3fe7 100644 --- a/module/type.go +++ b/module/type.go @@ -73,7 +73,7 @@ func (m *ModuleType[T]) CheckHealthy(ctx context.Context) (err error) { func (m *ModuleType[T]) valueWithBuilder(ctx *buildContext) T { ctx.deps[m.Name()] = struct{}{} - if ret, ok := ctx.modules[m.Name()]; ok { + if ret, ok := ctx.instances[m.Name()]; ok { return ret.(T) } @@ -82,19 +82,13 @@ func (m *ModuleType[T]) valueWithBuilder(ctx *buildContext) T { panic(errBuildError) } - return ctx.modules[m.Name()].(T) + return ctx.instances[m.Name()].(T) } func (m *ModuleType[T]) build(ctx *buildContext) error { - bctx := buildContext{ - Context: ctx.Context, - server: ctx.server, - deps: make(map[moduleName]struct{}), - modules: ctx.modules, - err: nil, - } + bctx := ctx.Child() - ret, err := m.builder(&bctx, bctx.server) + ret, err := m.builder(bctx, bctx.server) if err != nil { return err } @@ -104,7 +98,7 @@ func (m *ModuleType[T]) build(ctx *buildContext) error { m.depends = append(m.depends, name) } - ctx.modules[m.Name()] = ret + ctx.instances[m.Name()] = ret return nil }