From 461c532ed28198f93c99964b9be3eab397c36b84 Mon Sep 17 00:00:00 2001 From: Firas Darwish Date: Fri, 15 Nov 2024 13:50:34 +0300 Subject: [PATCH 01/12] removed `Lazy` keyword from funcs signatures --- README.md | 50 +++++++++--------- alias_test.go | 30 +++++------ benchmarks_test.go | 34 ++++++------ creator_test.go | 64 +++++++++++------------ eager_singleton_test.go | 30 +++++------ examples/benchperf/internal/DiOre.go | 22 ++++---- examples/placeholderdemo/main.go | 4 +- examples/shutdownerdemo/main.go | 4 +- examples/simple/main.go | 10 ++-- get_list_test.go | 10 ++-- get_test.go | 56 ++++++++++---------- initializer_test.go | 70 ++++++++++++------------- module_test.go | 4 +- ore_test.go | 6 +-- registrars.go | 44 ++++++++-------- registrars_placeholder_test.go | 20 +++---- validate_test.go | 78 ++++++++++++++-------------- 17 files changed, 268 insertions(+), 268 deletions(-) diff --git a/README.md b/README.md index 6d83eac..1001100 100644 --- a/README.md +++ b/README.md @@ -115,11 +115,11 @@ c.AddOne() ```go // register -ore.RegisterLazyCreator[Counter](ore.Scoped, &models.SimpleCounter{}) +ore.RegisterCreator[Counter](ore.Scoped, &models.SimpleCounter{}) // OR -//ore.RegisterLazyCreator[Counter](ore.Transient, &models.SimpleCounter{}) -//ore.RegisterLazyCreator[Counter](ore.Singleton, &models.SimpleCounter{}) +//ore.RegisterCreator[Counter](ore.Transient, &models.SimpleCounter{}) +//ore.RegisterCreator[Counter](ore.Singleton, &models.SimpleCounter{}) ctx := context.Background() @@ -142,17 +142,17 @@ fmt.Println("TOTAL: ", c.GetCount()) ```go // register -ore.RegisterLazyFunc[Counter](ore.Scoped, func(ctx context.Context) (Counter, context.Context) { +ore.RegisterFunc[Counter](ore.Scoped, func(ctx context.Context) (Counter, context.Context) { return &models.SimpleCounter{}, ctx }) // OR -//ore.RegisterLazyFunc[Counter](ore.Transient, func(ctx context.Context) (Counter, context.Context) { +//ore.RegisterFunc[Counter](ore.Transient, func(ctx context.Context) (Counter, context.Context) { // return &models.SimpleCounter{}, ctx //}) // Keyed service registration -//ore.RegisterLazyFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { +//ore.RegisterFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { // return &models.SimpleCounter{}, ctx //}, "name here", 1234) @@ -180,15 +180,15 @@ fmt.Println("TOTAL: ", c.GetCount()) ```go // register -ore.RegisterLazyCreator[Counter](ore.Scoped, &models.SimpleCounter{}) +ore.RegisterCreator[Counter](ore.Scoped, &models.SimpleCounter{}) -ore.RegisterLazyCreator[Counter](ore.Scoped, &yetAnotherCounter{}) +ore.RegisterCreator[Counter](ore.Scoped, &yetAnotherCounter{}) -ore.RegisterLazyFunc[Counter](ore.Transient, func(ctx context.Context) (Counter, context.Context) { +ore.RegisterFunc[Counter](ore.Transient, func(ctx context.Context) (Counter, context.Context) { return &models.SimpleCounter{}, ctx }) -ore.RegisterLazyCreator[Counter](ore.Singleton, &yetAnotherCounter{}) +ore.RegisterCreator[Counter](ore.Singleton, &yetAnotherCounter{}) ctx := context.Background() @@ -217,11 +217,11 @@ The last registered implementation takes precedence, so you can register a mock ```go // register -ore.RegisterLazyFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { +ore.RegisterFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { return &models.SimpleCounter{}, ctx }, "name here", 1234) -//ore.RegisterLazyCreator[Counter](ore.Scoped, &models.SimpleCounter{}, "name here", 1234) +//ore.RegisterCreator[Counter](ore.Scoped, &models.SimpleCounter{}, "name here", 1234) //ore.RegisterEagerSingleton[Counter](&models.SimpleCounter{}, "name here", 1234) @@ -249,13 +249,13 @@ type Trader struct { } //implements IPerson func TestGetInterfaceAlias(t *testing.T) { - ore.RegisterLazyFunc(ore.Scoped, func(ctx context.Context) (*Broker, context.Context) { + ore.RegisterFunc(ore.Scoped, func(ctx context.Context) (*Broker, context.Context) { return &Broker{Name: "Peter"}, ctx }) - ore.RegisterLazyFunc(ore.Scoped, func(ctx context.Context) (*Broker, context.Context) { + ore.RegisterFunc(ore.Scoped, func(ctx context.Context) (*Broker, context.Context) { return &Broker{Name: "John"}, ctx }) - ore.RegisterLazyFunc(ore.Scoped, func(ctx context.Context) (*Trader, context.Context) { + ore.RegisterFunc(ore.Scoped, func(ctx context.Context) (*Trader, context.Context) { return &Trader{Name: "Mary"}, ctx }) @@ -360,7 +360,7 @@ Here how Ore can help you: type Disposer interface { Dispose() } -ore.RegisterLazyCreator(ore.Scoped, &SomeDisposableService{}) //*SomeDisposableService implements Disposer +ore.RegisterCreator(ore.Scoped, &SomeDisposableService{}) //*SomeDisposableService implements Disposer //a new request arrive ctx, cancel := context.WithCancel(context.Background()) @@ -399,8 +399,8 @@ The `ore.GetResolvedScopedInstances[TInterface](context)` function returns a lis | GetResolvedSingletons | GetResolvedSingletonsFromContainer | | RegisterAlias | RegisterAliasToContainer | | RegisterEagerSingleton | RegisterEagerSingletonToContainer | -| RegisterLazyCreator | RegisterLazyCreatorToContainer | -| RegisterLazyFunc | RegisterLazyFuncToContainer | +| RegisterCreator | RegisterCreatorToContainer | +| RegisterFunc | RegisterFuncToContainer | | RegisterPlaceHolder | RegisterPlaceHolderToContainer | | ProvideScopedValue | ProvideScopedValueToContainer | @@ -409,7 +409,7 @@ Most of time you only need the Default Container. In rare use case such as the M ```go //broker module brokerContainer := ore.NewContainer() -ore.RegisterLazyFuncToContainer(brokerContainer, ore.Singleton, func(ctx context.Context) (*Broker, context.Context) { +ore.RegisterFuncToContainer(brokerContainer, ore.Singleton, func(ctx context.Context) (*Broker, context.Context) { brs, ctx = ore.GetFromContainer[*BrokerageSystem](brokerContainer, ctx) return &Broker{brs}, ctx }) @@ -420,7 +420,7 @@ broker, _ := ore.GetFromContainer[*Broker](brokerContainer, context.Background() //trader module traderContainer := ore.NewContainer() -ore.RegisterLazyFuncToContainer(traderContainer, ore.Singleton, func(ctx context.Context) (*Trader, context.Context) { +ore.RegisterFuncToContainer(traderContainer, ore.Singleton, func(ctx context.Context) (*Trader, context.Context) { mkp, ctx = ore.GetFromContainer[*MarketPlace](traderContainer, ctx) return &Trader{mkp}, ctx }) @@ -438,7 +438,7 @@ A common scenario is that your "Service" depends on something which you couldn't ```go //register SomeService which depends on "someConfig" -ore.RegisterLazyFunc[*SomeService](ore.Scoped, func(ctx context.Context) (*SomeService, context.Context) { +ore.RegisterFunc[*SomeService](ore.Scoped, func(ctx context.Context) (*SomeService, context.Context) { someConfig, ctx := ore.Get[string](ctx, "someConfig") return &SomeService{someConfig}, ctx }) @@ -480,7 +480,7 @@ fmt.Println(service.someConfig) //"Admin config" - `ore.ProvideScopedValue[T](context, value T, key...)` injects a concrete value into the given context - `ore` can access (`Get()` or `GetList()`) to this value only if the corresponding placeholder (which matches the type and keys) is registered. -- A value provided to a placeholder would never replace value returned by other resolvers. It's the opposite, if a type (and key) could be resolved by a real resolver (such as `RegisterLazyFunc`, `RegisterLazyCreator`...), then the later would take precedent. +- A value provided to a placeholder would never replace value returned by other resolvers. It's the opposite, if a type (and key) could be resolved by a real resolver (such as `RegisterFunc`, `RegisterCreator`...), then the later would take precedent.
@@ -513,7 +513,7 @@ func (gc *genericCounter[T]) GetCount(ctx context.Context) T { ```go // register -ore.RegisterLazyFunc[GenericCounter[int]](ore.Scoped, func(ctx context.Context) (GenericCounter[int], context.Context) { +ore.RegisterFunc[GenericCounter[int]](ore.Scoped, func(ctx context.Context) (GenericCounter[int], context.Context) { return &genericCounter[int]{}, ctx }) @@ -530,8 +530,8 @@ goos: windows goarch: amd64 pkg: github.com/firasdarwish/ore cpu: 13th Gen Intel(R) Core(TM) i9-13900H -BenchmarkRegisterLazyFunc-20 5706694 196.9 ns/op -BenchmarkRegisterLazyCreator-20 6283534 184.5 ns/op +BenchmarkRegisterFunc-20 5706694 196.9 ns/op +BenchmarkRegisterCreator-20 6283534 184.5 ns/op BenchmarkRegisterEagerSingleton-20 5146953 211.5 ns/op BenchmarkInitialGet-20 3440072 352.1 ns/op BenchmarkGet-20 9806043 121.8 ns/op diff --git a/alias_test.go b/alias_test.go index d285b25..52c0088 100644 --- a/alias_test.go +++ b/alias_test.go @@ -11,10 +11,10 @@ import ( func TestAliasResolverConflict(t *testing.T) { clearAll() - RegisterLazyFunc(Singleton, func(ctx context.Context) (m.IPerson, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (m.IPerson, context.Context) { return &m.Trader{Name: "Peter Singleton"}, ctx }) - RegisterLazyFunc(Transient, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterFunc(Transient, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "Mary Transient"}, ctx }) @@ -36,10 +36,10 @@ func TestAliasResolverConflict(t *testing.T) { func TestAliasOfAliasIsNotAllow(t *testing.T) { clearAll() - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.Trader, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.Trader, context.Context) { return &m.Trader{Name: "Peter Singleton"}, ctx }) - RegisterLazyFunc(Transient, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterFunc(Transient, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "Mary Transient"}, ctx }) @@ -58,13 +58,13 @@ func TestAliasOfAliasIsNotAllow(t *testing.T) { func TestAliasWithDifferentScope(t *testing.T) { clearAll() module := "TestGetInterfaceAliasWithDifferentScope" - RegisterLazyFunc(Transient, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterFunc(Transient, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "Transient"}, ctx }, module) - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "Singleton"}, ctx }, module) - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "Scoped"}, ctx }, module) RegisterAlias[m.IPerson, *m.Broker]() //link m.IPerson to *m.Broker @@ -80,24 +80,24 @@ func TestAliasWithDifferentScope(t *testing.T) { func TestAliasIsScopedByKeys(t *testing.T) { clearAll() - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "Peter1"}, ctx }, "module1") - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "John1"}, ctx }, "module1") - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.Trader, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.Trader, context.Context) { return &m.Trader{Name: "Mary1"}, ctx }, "module1") - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "John2"}, ctx }, "module2") - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.Trader, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.Trader, context.Context) { return &m.Trader{Name: "Mary2"}, ctx }, "module2") - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.Trader, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.Trader, context.Context) { return &m.Trader{Name: "Mary3"}, ctx }, "module3") @@ -138,7 +138,7 @@ func TestGetGenericAlias(t *testing.T) { for _, registrationType := range types { container := NewContainer() - RegisterLazyFuncToContainer(container, registrationType, func(ctx context.Context) (*m.SimpleCounterUint, context.Context) { + RegisterFuncToContainer(container, registrationType, func(ctx context.Context) (*m.SimpleCounterUint, context.Context) { return &m.SimpleCounterUint{}, ctx }) RegisterAliasToContainer[interfaces.SomeCounterGeneric[uint], *m.SimpleCounterUint](container) @@ -157,7 +157,7 @@ func TestGetListGenericAlias(t *testing.T) { container := NewContainer() for i := 0; i < 3; i++ { - RegisterLazyFuncToContainer(container, registrationType, func(ctx context.Context) (*m.SimpleCounterUint, context.Context) { + RegisterFuncToContainer(container, registrationType, func(ctx context.Context) (*m.SimpleCounterUint, context.Context) { return &m.SimpleCounterUint{}, ctx }) } diff --git a/benchmarks_test.go b/benchmarks_test.go index f7a9136..0f63f1b 100644 --- a/benchmarks_test.go +++ b/benchmarks_test.go @@ -7,23 +7,23 @@ import ( "testing" ) -func BenchmarkRegisterLazyFunc(b *testing.B) { +func BenchmarkRegisterFunc(b *testing.B) { clearAll() b.ResetTimer() for i := 0; i < b.N; i++ { - RegisterLazyFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }) } } -func BenchmarkRegisterLazyCreator(b *testing.B) { +func BenchmarkRegisterCreator(b *testing.B) { clearAll() b.ResetTimer() for i := 0; i < b.N; i++ { - RegisterLazyCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) } } @@ -32,20 +32,20 @@ func BenchmarkRegisterEagerSingleton(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) } } func BenchmarkInitialGet(b *testing.B) { clearAll() - RegisterLazyFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }) - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) - RegisterLazyCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) Seal() Validate() @@ -61,13 +61,13 @@ func BenchmarkInitialGet(b *testing.B) { func BenchmarkGet(b *testing.B) { clearAll() - RegisterLazyFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }) - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) - RegisterLazyCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) Seal() Validate() ctx := context.Background() @@ -81,13 +81,13 @@ func BenchmarkGet(b *testing.B) { func BenchmarkInitialGetList(b *testing.B) { clearAll() - RegisterLazyFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }) - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) - RegisterLazyCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) Seal() Validate() @@ -102,13 +102,13 @@ func BenchmarkInitialGetList(b *testing.B) { func BenchmarkGetList(b *testing.B) { clearAll() - RegisterLazyFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }) - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) - RegisterLazyCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) Seal() Validate() ctx := context.Background() diff --git a/creator_test.go b/creator_test.go index 231103c..693c9bc 100644 --- a/creator_test.go +++ b/creator_test.go @@ -9,11 +9,11 @@ import ( "github.com/stretchr/testify/assert" ) -func TestRegisterLazyCreator(t *testing.T) { +func TestRegisterCreator(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) c, _ := Get[interfaces.SomeCounter](context.Background()) @@ -26,36 +26,36 @@ func TestRegisterLazyCreator(t *testing.T) { } } -func TestRegisterLazyCreatorNilFuncTransient(t *testing.T) { +func TestRegisterCreatorNilFuncTransient(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterLazyCreator[interfaces.SomeCounter](Transient, nil) + RegisterCreator[interfaces.SomeCounter](Transient, nil) }) } -func TestRegisterLazyCreatorNilFuncScoped(t *testing.T) { +func TestRegisterCreatorNilFuncScoped(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterLazyCreator[interfaces.SomeCounter](Scoped, nil) + RegisterCreator[interfaces.SomeCounter](Scoped, nil) }) } -func TestRegisterLazyCreatorNilFuncSingleton(t *testing.T) { +func TestRegisterCreatorNilFuncSingleton(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterLazyCreator[interfaces.SomeCounter](Singleton, nil) + RegisterCreator[interfaces.SomeCounter](Singleton, nil) }) } -func TestRegisterLazyCreatorMultipleImplementations(t *testing.T) { +func TestRegisterCreatorMultipleImplementations(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) counters, _ := GetList[interfaces.SomeCounter](context.Background()) @@ -65,15 +65,15 @@ func TestRegisterLazyCreatorMultipleImplementations(t *testing.T) { } } -func TestRegisterLazyCreatorMultipleImplementationsKeyed(t *testing.T) { +func TestRegisterCreatorMultipleImplementationsKeyed(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, "firas") + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, "firas") - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, "firas") + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, "firas") - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) counters, _ := GetList[interfaces.SomeCounter](context.Background(), "firas") @@ -83,12 +83,12 @@ func TestRegisterLazyCreatorMultipleImplementationsKeyed(t *testing.T) { } } -func TestRegisterLazyCreatorSingletonState(t *testing.T) { +func TestRegisterCreatorSingletonState(t *testing.T) { var registrationType Lifetime = Singleton clearAll() - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) c, _ := Get[interfaces.SomeCounter](context.Background()) c.AddOne() @@ -107,12 +107,12 @@ func TestRegisterLazyCreatorSingletonState(t *testing.T) { } } -func TestRegisterLazyCreatorScopedState(t *testing.T) { +func TestRegisterCreatorScopedState(t *testing.T) { var registrationType Lifetime = Scoped clearAll() - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) ctx := context.Background() @@ -133,12 +133,12 @@ func TestRegisterLazyCreatorScopedState(t *testing.T) { } } -func TestRegisterLazyCreatorTransientState(t *testing.T) { +func TestRegisterCreatorTransientState(t *testing.T) { var registrationType Lifetime = Transient clearAll() - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) ctx := context.Background() @@ -159,26 +159,26 @@ func TestRegisterLazyCreatorTransientState(t *testing.T) { } } -func TestRegisterLazyCreatorNilKeyOnRegistering(t *testing.T) { +func TestRegisterCreatorNilKeyOnRegistering(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterLazyCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}, "", nil) + RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}, "", nil) }) } -func TestRegisterLazyCreatorNilKeyOnGetting(t *testing.T) { +func TestRegisterCreatorNilKeyOnGetting(t *testing.T) { clearAll() - RegisterLazyCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}, "firas") + RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}, "firas") assert.Panics(t, func() { Get[interfaces.SomeCounter](context.Background(), nil) }) } -func TestRegisterLazyCreatorGeneric(t *testing.T) { +func TestRegisterCreatorGeneric(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterLazyCreator[interfaces.SomeCounterGeneric[uint]](registrationType, &models.CounterGeneric[uint]{}) + RegisterCreator[interfaces.SomeCounterGeneric[uint]](registrationType, &models.CounterGeneric[uint]{}) c, _ := Get[interfaces.SomeCounterGeneric[uint]](context.Background()) @@ -191,15 +191,15 @@ func TestRegisterLazyCreatorGeneric(t *testing.T) { } } -func TestRegisterLazyCreatorMultipleGenericImplementations(t *testing.T) { +func TestRegisterCreatorMultipleGenericImplementations(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterLazyCreator[interfaces.SomeCounterGeneric[uint]](registrationType, &models.CounterGeneric[uint]{}) + RegisterCreator[interfaces.SomeCounterGeneric[uint]](registrationType, &models.CounterGeneric[uint]{}) - RegisterLazyCreator[interfaces.SomeCounterGeneric[uint]](registrationType, &models.CounterGeneric[uint]{}) + RegisterCreator[interfaces.SomeCounterGeneric[uint]](registrationType, &models.CounterGeneric[uint]{}) - RegisterLazyCreator[interfaces.SomeCounterGeneric[uint]](registrationType, &models.CounterGeneric[uint]{}) + RegisterCreator[interfaces.SomeCounterGeneric[uint]](registrationType, &models.CounterGeneric[uint]{}) counters, _ := GetList[interfaces.SomeCounterGeneric[uint]](context.Background()) diff --git a/eager_singleton_test.go b/eager_singleton_test.go index 10d6548..089154a 100644 --- a/eager_singleton_test.go +++ b/eager_singleton_test.go @@ -12,7 +12,7 @@ import ( func TestRegisterEagerSingleton(t *testing.T) { clearAll() - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) c, _ := Get[interfaces.SomeCounter](context.Background()) @@ -27,16 +27,16 @@ func TestRegisterEagerSingleton(t *testing.T) { func TestRegisterEagerSingletonNilImplementation(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterEagerSingleton[interfaces.SomeCounter](nil) + RegisterSingleton[interfaces.SomeCounter](nil) }) } func TestRegisterEagerSingletonMultipleImplementations(t *testing.T) { clearAll() - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) counters, _ := GetList[interfaces.SomeCounter](context.Background()) @@ -48,10 +48,10 @@ func TestRegisterEagerSingletonMultipleImplementations(t *testing.T) { func TestRegisterEagerSingletonMultipleImplementationsKeyed(t *testing.T) { clearAll() - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) counters, _ := GetList[interfaces.SomeCounter](context.Background(), "firas") @@ -63,7 +63,7 @@ func TestRegisterEagerSingletonMultipleImplementationsKeyed(t *testing.T) { func TestRegisterEagerSingletonSingletonState(t *testing.T) { clearAll() - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) c, _ := Get[interfaces.SomeCounter](context.Background()) c.AddOne() @@ -85,13 +85,13 @@ func TestRegisterEagerSingletonSingletonState(t *testing.T) { func TestRegisterEagerSingletonNilKeyOnRegistering(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, nil, "") + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, nil, "") }) } func TestRegisterEagerSingletonNilKeyOnGetting(t *testing.T) { clearAll() - RegisterEagerSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") + RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") assert.Panics(t, func() { Get[interfaces.SomeCounter](context.Background(), nil, "") }) @@ -100,7 +100,7 @@ func TestRegisterEagerSingletonNilKeyOnGetting(t *testing.T) { func TestRegisterEagerSingletonGeneric(t *testing.T) { clearAll() - RegisterEagerSingleton[interfaces.SomeCounterGeneric[uint]](&models.CounterGeneric[uint]{}) + RegisterSingleton[interfaces.SomeCounterGeneric[uint]](&models.CounterGeneric[uint]{}) c, _ := Get[interfaces.SomeCounterGeneric[uint]](context.Background()) @@ -115,9 +115,9 @@ func TestRegisterEagerSingletonGeneric(t *testing.T) { func TestRegisterEagerSingletonMultipleGenericImplementations(t *testing.T) { clearAll() - RegisterEagerSingleton[interfaces.SomeCounterGeneric[uint]](&models.CounterGeneric[uint]{}) - RegisterEagerSingleton[interfaces.SomeCounterGeneric[uint]](&models.CounterGeneric[uint]{}) - RegisterEagerSingleton[interfaces.SomeCounterGeneric[uint]](&models.CounterGeneric[uint]{}) + RegisterSingleton[interfaces.SomeCounterGeneric[uint]](&models.CounterGeneric[uint]{}) + RegisterSingleton[interfaces.SomeCounterGeneric[uint]](&models.CounterGeneric[uint]{}) + RegisterSingleton[interfaces.SomeCounterGeneric[uint]](&models.CounterGeneric[uint]{}) counters, _ := GetList[interfaces.SomeCounterGeneric[uint]](context.Background()) diff --git a/examples/benchperf/internal/DiOre.go b/examples/benchperf/internal/DiOre.go index e248b56..93f7804 100644 --- a/examples/benchperf/internal/DiOre.go +++ b/examples/benchperf/internal/DiOre.go @@ -14,45 +14,45 @@ func BuildContainerOre(disableValidation bool) *ore.Container { } func RegisterToOreContainer(container *ore.Container) { - ore.RegisterLazyFuncToContainer(container, ore.Transient, func(ctx context.Context) (*A, context.Context) { + ore.RegisterFuncToContainer(container, ore.Transient, func(ctx context.Context) (*A, context.Context) { b, ctx := ore.GetFromContainer[*B](container, ctx) c, ctx := ore.GetFromContainer[*C](container, ctx) return NewA(b, c), ctx }) - ore.RegisterLazyFuncToContainer(container, ore.Transient, func(ctx context.Context) (*B, context.Context) { + ore.RegisterFuncToContainer(container, ore.Transient, func(ctx context.Context) (*B, context.Context) { d, ctx := ore.GetFromContainer[*D](container, ctx) e, ctx := ore.GetFromContainer[*E](container, ctx) return NewB(d, e), ctx }) - ore.RegisterLazyFuncToContainer(container, ore.Transient, func(ctx context.Context) (*C, context.Context) { + ore.RegisterFuncToContainer(container, ore.Transient, func(ctx context.Context) (*C, context.Context) { return NewC(), ctx }) - ore.RegisterLazyFuncToContainer(container, ore.Transient, func(ctx context.Context) (*D, context.Context) { + ore.RegisterFuncToContainer(container, ore.Transient, func(ctx context.Context) (*D, context.Context) { f, ctx := ore.GetFromContainer[*F](container, ctx) h, ctx := ore.GetFromContainer[H](container, ctx) return NewD(f, h), ctx }) - ore.RegisterLazyFuncToContainer(container, ore.Transient, func(ctx context.Context) (*E, context.Context) { + ore.RegisterFuncToContainer(container, ore.Transient, func(ctx context.Context) (*E, context.Context) { gs, ctx := ore.GetListFromContainer[G](container, ctx) return NewE(gs), ctx }) - ore.RegisterLazyFuncToContainer(container, ore.Singleton, func(ctx context.Context) (*F, context.Context) { + ore.RegisterFuncToContainer(container, ore.Singleton, func(ctx context.Context) (*F, context.Context) { return NewF(), ctx }) - ore.RegisterLazyFuncToContainer(container, ore.Transient, func(ctx context.Context) (*Ga, context.Context) { + ore.RegisterFuncToContainer(container, ore.Transient, func(ctx context.Context) (*Ga, context.Context) { return NewGa(), ctx }) - ore.RegisterLazyFuncToContainer(container, ore.Singleton, func(ctx context.Context) (G, context.Context) { + ore.RegisterFuncToContainer(container, ore.Singleton, func(ctx context.Context) (G, context.Context) { return NewGb(), ctx }) - ore.RegisterLazyFuncToContainer(container, ore.Transient, func(ctx context.Context) (G, context.Context) { + ore.RegisterFuncToContainer(container, ore.Transient, func(ctx context.Context) (G, context.Context) { return NewGc(), ctx }) - ore.RegisterLazyFuncToContainer(container, ore.Transient, func(ctx context.Context) (G, context.Context) { + ore.RegisterFuncToContainer(container, ore.Transient, func(ctx context.Context) (G, context.Context) { ga, ctx := ore.GetFromContainer[*Ga](container, ctx) return NewDGa(ga), ctx }) - ore.RegisterLazyFuncToContainer(container, ore.Transient, func(ctx context.Context) (H, context.Context) { + ore.RegisterFuncToContainer(container, ore.Transient, func(ctx context.Context) (H, context.Context) { return NewHr(), ctx }) } diff --git a/examples/placeholderdemo/main.go b/examples/placeholderdemo/main.go index df90e9a..5460b59 100644 --- a/examples/placeholderdemo/main.go +++ b/examples/placeholderdemo/main.go @@ -15,14 +15,14 @@ type SomeService struct { func main() { //register SomeService which depends on "someConfig" - ore.RegisterLazyFunc[*SomeService](ore.Scoped, func(ctx context.Context) (*SomeService, context.Context) { + ore.RegisterFunc[*SomeService](ore.Scoped, func(ctx context.Context) (*SomeService, context.Context) { someConfig, ctx := ore.Get[string](ctx, "someConfig") return &SomeService{someConfig}, ctx }) //someConfig is unknow at registration time //the value of "someConfig" depends on the future user's request - ore.RegisterPlaceHolder[string]("someConfig") + ore.RegisterPlaceholder[string]("someConfig") //Seal registration, no further registration is allowed ore.Seal() diff --git a/examples/shutdownerdemo/main.go b/examples/shutdownerdemo/main.go index d300197..b65bae6 100644 --- a/examples/shutdownerdemo/main.go +++ b/examples/shutdownerdemo/main.go @@ -41,8 +41,8 @@ func (*myScopedRepo) New(ctx context.Context) (*myScopedRepo, context.Context) { } func main() { - ore.RegisterEagerSingleton[*myGlobalRepo](&myGlobalRepo{}) - ore.RegisterLazyCreator(ore.Scoped, &myScopedRepo{}) + ore.RegisterSingleton[*myGlobalRepo](&myGlobalRepo{}) + ore.RegisterCreator(ore.Scoped, &myScopedRepo{}) ore.Validate() diff --git a/examples/simple/main.go b/examples/simple/main.go index 05c9c33..2840fbd 100644 --- a/examples/simple/main.go +++ b/examples/simple/main.go @@ -8,20 +8,20 @@ import ( ) func main() { - ore.RegisterLazyFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { + ore.RegisterFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { fmt.Println("NEWLY INITIALIZED FROM FUNC") return &mycounter{}, ctx }, "firas") - ore.RegisterLazyFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { + ore.RegisterFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { fmt.Println("NEWLY INITIALIZED FROM FUNC") return &mycounter{}, ctx }, "darwish") - ore.RegisterLazyCreator[Counter](ore.Singleton, &mycounter{}) + ore.RegisterCreator[Counter](ore.Singleton, &mycounter{}) cc := &mycounter{} - ore.RegisterEagerSingleton[Counter](cc) + ore.RegisterSingleton[Counter](cc) ctx := context.Background() @@ -37,7 +37,7 @@ func main() { fmt.Printf("Total Count: %v", c.Total()) - ore.RegisterLazyCreator[GenericCounter[uint]](ore.Scoped, &genCounter[uint]{}) + ore.RegisterCreator[GenericCounter[uint]](ore.Scoped, &genCounter[uint]{}) gc, ctx := ore.Get[GenericCounter[uint]](ctx) gc.Add(1) diff --git a/get_list_test.go b/get_list_test.go index 2803345..e044425 100644 --- a/get_list_test.go +++ b/get_list_test.go @@ -11,7 +11,7 @@ func TestGetList(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) counters, _ := GetList[interfaces.SomeCounter](context.Background()) @@ -35,10 +35,10 @@ func TestGetListKeyed(t *testing.T) { key := "somekeyhere" - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, key) - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, key) - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, key) - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, "Firas") + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, key) + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, key) + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, key) + RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, "Firas") counters, _ := GetList[interfaces.SomeCounter](context.Background(), key) if got := len(counters); got != 3 { diff --git a/get_test.go b/get_test.go index 40366ae..369a32f 100644 --- a/get_test.go +++ b/get_test.go @@ -15,7 +15,7 @@ func TestGet(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &m.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](registrationType, &m.SimpleCounter{}) c, _ := Get[interfaces.SomeCounter](context.Background()) @@ -32,12 +32,12 @@ func TestGetLatestByDefault(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &m.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](registrationType, &m.SimpleCounter{}) c, _ := Get[interfaces.SomeCounter](context.Background()) c.AddOne() c.AddOne() - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &m.SimpleCounter2{}) + RegisterCreator[interfaces.SomeCounter](registrationType, &m.SimpleCounter2{}) c, _ = Get[interfaces.SomeCounter](context.Background()) c.AddOne() c.AddOne() @@ -63,7 +63,7 @@ func TestGetKeyed(t *testing.T) { key := fmt.Sprintf("keynum: %v", i) - RegisterLazyCreator[interfaces.SomeCounter](registrationType, &m.SimpleCounter{}, key) + RegisterCreator[interfaces.SomeCounter](registrationType, &m.SimpleCounter{}, key) c, _ := Get[interfaces.SomeCounter](context.Background(), key) @@ -80,24 +80,24 @@ func TestGetResolvedSingletons(t *testing.T) { t.Run("When multiple lifetimes and keys are registered", func(t *testing.T) { //Arrange clearAll() - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService1, context.Context) { return &m.DisposableService1{Name: "A1"}, ctx }) - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService1, context.Context) { return &m.DisposableService1{Name: "A2"}, ctx }) - RegisterEagerSingleton(&m.DisposableService2{Name: "E1"}) - RegisterEagerSingleton(&m.DisposableService2{Name: "E2"}) - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterSingleton(&m.DisposableService2{Name: "E1"}) + RegisterSingleton(&m.DisposableService2{Name: "E2"}) + RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService3, context.Context) { return &m.DisposableService3{Name: "S1"}, ctx }) - RegisterLazyFunc(Transient, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterFunc(Transient, func(ctx context.Context) (*m.DisposableService3, context.Context) { return &m.DisposableService3{Name: "S2"}, ctx }) - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService4, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService4, context.Context) { return &m.DisposableService4{Name: "X1"}, ctx }) - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService4, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService4, context.Context) { return &m.DisposableService4{Name: "X2"}, ctx }, "somekey") @@ -135,13 +135,13 @@ func TestGetResolvedSingletons(t *testing.T) { t.Run("respect invocation chronological time order", func(t *testing.T) { //Arrange clearAll() - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService1, context.Context) { return &m.DisposableService1{Name: "A"}, ctx }) - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService2, context.Context) { return &m.DisposableService2{Name: "B"}, ctx }) - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService3, context.Context) { return &m.DisposableService3{Name: "C"}, ctx }) @@ -166,15 +166,15 @@ func TestGetResolvedSingletons(t *testing.T) { t.Run("deeper invocation level is returned first", func(t *testing.T) { //Arrange clearAll() - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService1, context.Context) { _, ctx = Get[*m.DisposableService2](ctx) //1 calls 2 return &m.DisposableService1{Name: "1"}, ctx }) - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService2, context.Context) { _, ctx = Get[*m.DisposableService3](ctx) //2 calls 3 return &m.DisposableService2{Name: "2"}, ctx }) - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService3, context.Context) { return &m.DisposableService3{Name: "3"}, ctx }) @@ -195,11 +195,11 @@ func TestGetResolvedSingletons(t *testing.T) { func TestGetResolvedScopedInstances(t *testing.T) { t.Run("When multiple lifetimes and keys are registered", func(t *testing.T) { clearAll() - RegisterEagerSingleton(&m.DisposableService1{Name: "S1"}) - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterSingleton(&m.DisposableService1{Name: "S1"}) + RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService1, context.Context) { return &m.DisposableService1{Name: "S2"}, ctx }) - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { return &m.DisposableService2{Name: "T1"}, ctx }, "module1") @@ -228,13 +228,13 @@ func TestGetResolvedScopedInstances(t *testing.T) { t.Run("respect invocation chronological time order", func(t *testing.T) { //Arrange clearAll() - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService1, context.Context) { return &m.DisposableService1{Name: "A"}, ctx }) - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { return &m.DisposableService2{Name: "B"}, ctx }) - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService3, context.Context) { return &m.DisposableService3{Name: "C"}, ctx }) @@ -260,18 +260,18 @@ func TestGetResolvedScopedInstances(t *testing.T) { t.Run("respect invocation deep level", func(t *testing.T) { //Arrange clearAll() - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService1, context.Context) { //1 calls 3 _, ctx = Get[*m.DisposableService3](ctx) return &m.DisposableService1{Name: "1"}, ctx }) - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { return &m.DisposableService2{Name: "2"}, ctx }) - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService3, context.Context) { return &m.DisposableService3{Name: "3"}, ctx }) - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.DisposableService4, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService4, context.Context) { //4 calls 1, 2 _, ctx = Get[*m.DisposableService1](ctx) _, ctx = Get[*m.DisposableService2](ctx) diff --git a/initializer_test.go b/initializer_test.go index 10c2d75..06603c3 100644 --- a/initializer_test.go +++ b/initializer_test.go @@ -9,11 +9,11 @@ import ( "github.com/stretchr/testify/assert" ) -func TestRegisterLazyFunc(t *testing.T) { +func TestRegisterFunc(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterLazyFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }) @@ -28,40 +28,40 @@ func TestRegisterLazyFunc(t *testing.T) { } } -func TestRegisterLazyFuncNilFuncTransient(t *testing.T) { +func TestRegisterFuncNilFuncTransient(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterLazyFunc[interfaces.SomeCounter](Transient, nil) + RegisterFunc[interfaces.SomeCounter](Transient, nil) }) } -func TestRegisterLazyFuncNilFuncScoped(t *testing.T) { +func TestRegisterFuncNilFuncScoped(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterLazyFunc[interfaces.SomeCounter](Scoped, nil) + RegisterFunc[interfaces.SomeCounter](Scoped, nil) }) } -func TestRegisterLazyFuncNilFuncSingleton(t *testing.T) { +func TestRegisterFuncNilFuncSingleton(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterLazyFunc[interfaces.SomeCounter](Singleton, nil) + RegisterFunc[interfaces.SomeCounter](Singleton, nil) }) } -func TestRegisterLazyFuncMultipleImplementations(t *testing.T) { +func TestRegisterFuncMultipleImplementations(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterLazyFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }) - RegisterLazyFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }) - RegisterLazyFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }) @@ -73,19 +73,19 @@ func TestRegisterLazyFuncMultipleImplementations(t *testing.T) { } } -func TestRegisterLazyFuncMultipleImplementationsKeyed(t *testing.T) { +func TestRegisterFuncMultipleImplementationsKeyed(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterLazyFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }, "firas") - RegisterLazyFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }, "firas") - RegisterLazyFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }) @@ -97,12 +97,12 @@ func TestRegisterLazyFuncMultipleImplementationsKeyed(t *testing.T) { } } -func TestRegisterLazyFuncSingletonState(t *testing.T) { +func TestRegisterFuncSingletonState(t *testing.T) { var registrationType Lifetime = Singleton clearAll() - RegisterLazyFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }) @@ -123,12 +123,12 @@ func TestRegisterLazyFuncSingletonState(t *testing.T) { } } -func TestRegisterLazyFuncScopedState(t *testing.T) { +func TestRegisterFuncScopedState(t *testing.T) { var registrationType Lifetime = Scoped clearAll() - RegisterLazyFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }) @@ -151,12 +151,12 @@ func TestRegisterLazyFuncScopedState(t *testing.T) { } } -func TestRegisterLazyFuncTransientState(t *testing.T) { +func TestRegisterFuncTransientState(t *testing.T) { var registrationType Lifetime = Transient clearAll() - RegisterLazyFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }) @@ -179,18 +179,18 @@ func TestRegisterLazyFuncTransientState(t *testing.T) { } } -func TestRegisterLazyFuncNilKeyOnRegistering(t *testing.T) { +func TestRegisterFuncNilKeyOnRegistering(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterLazyFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }, "", nil) }) } -func TestRegisterLazyFuncNilKeyOnGetting(t *testing.T) { +func TestRegisterFuncNilKeyOnGetting(t *testing.T) { clearAll() - RegisterLazyFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }, "firas") @@ -199,11 +199,11 @@ func TestRegisterLazyFuncNilKeyOnGetting(t *testing.T) { }) } -func TestRegisterLazyFuncGeneric(t *testing.T) { +func TestRegisterFuncGeneric(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterLazyFunc[interfaces.SomeCounterGeneric[uint]](registrationType, func(ctx context.Context) (interfaces.SomeCounterGeneric[uint], context.Context) { + RegisterFunc[interfaces.SomeCounterGeneric[uint]](registrationType, func(ctx context.Context) (interfaces.SomeCounterGeneric[uint], context.Context) { return &models.CounterGeneric[uint]{}, ctx }) @@ -218,19 +218,19 @@ func TestRegisterLazyFuncGeneric(t *testing.T) { } } -func TestRegisterLazyFuncMultipleGenericImplementations(t *testing.T) { +func TestRegisterFuncMultipleGenericImplementations(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterLazyFunc[interfaces.SomeCounterGeneric[uint]](registrationType, func(ctx context.Context) (interfaces.SomeCounterGeneric[uint], context.Context) { + RegisterFunc[interfaces.SomeCounterGeneric[uint]](registrationType, func(ctx context.Context) (interfaces.SomeCounterGeneric[uint], context.Context) { return &models.CounterGeneric[uint]{}, ctx }) - RegisterLazyFunc[interfaces.SomeCounterGeneric[uint]](registrationType, func(ctx context.Context) (interfaces.SomeCounterGeneric[uint], context.Context) { + RegisterFunc[interfaces.SomeCounterGeneric[uint]](registrationType, func(ctx context.Context) (interfaces.SomeCounterGeneric[uint], context.Context) { return &models.CounterGeneric[uint]{}, ctx }) - RegisterLazyFunc[interfaces.SomeCounterGeneric[uint]](registrationType, func(ctx context.Context) (interfaces.SomeCounterGeneric[uint], context.Context) { + RegisterFunc[interfaces.SomeCounterGeneric[uint]](registrationType, func(ctx context.Context) (interfaces.SomeCounterGeneric[uint], context.Context) { return &models.CounterGeneric[uint]{}, ctx }) @@ -242,17 +242,17 @@ func TestRegisterLazyFuncMultipleGenericImplementations(t *testing.T) { } } -func TestRegisterLazyFuncScopedNested(t *testing.T) { +func TestRegisterFuncScopedNested(t *testing.T) { clearAll() - RegisterLazyFunc[*models.A](Transient, func(ctx context.Context) (*models.A, context.Context) { + RegisterFunc[*models.A](Transient, func(ctx context.Context) (*models.A, context.Context) { cc, ctx := Get[*models.C](ctx) return &models.A{ C: cc, }, ctx }) - RegisterLazyFunc[*models.C](Scoped, func(ctx context.Context) (*models.C, context.Context) { + RegisterFunc[*models.C](Scoped, func(ctx context.Context) (*models.C, context.Context) { return &models.C{}, ctx }) diff --git a/module_test.go b/module_test.go index 8d22208..056f9e5 100644 --- a/module_test.go +++ b/module_test.go @@ -13,12 +13,12 @@ func TestModuleIsolation(t *testing.T) { for _, lifetime := range types { t.Run(fmt.Sprintf("Module isolation %s", lifetime), func(t *testing.T) { con1 := NewContainer() - RegisterLazyFuncToContainer(con1, lifetime, func(ctx context.Context) (*m.Trader, context.Context) { + RegisterFuncToContainer(con1, lifetime, func(ctx context.Context) (*m.Trader, context.Context) { return &m.Trader{Name: "John"}, ctx }) con2 := NewContainer() - RegisterLazyFuncToContainer(con2, lifetime, func(ctx context.Context) (*m.Trader, context.Context) { + RegisterFuncToContainer(con2, lifetime, func(ctx context.Context) (*m.Trader, context.Context) { return &m.Trader{Name: "Mary"}, ctx }) diff --git a/ore_test.go b/ore_test.go index 95dca54..8c98f3d 100644 --- a/ore_test.go +++ b/ore_test.go @@ -10,16 +10,16 @@ import ( func TestSeal(t *testing.T) { clearAll() - RegisterLazyCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) Seal() assert.Panics(t, func() { - RegisterLazyCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) }) } func TestIsSeal(t *testing.T) { clearAll() - RegisterLazyCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) + RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) if got := IsSealed(); got != false { t.Errorf("IsSealed() = %v; want %v", got, false) } diff --git a/registrars.go b/registrars.go index 26cddca..7e3a258 100644 --- a/registrars.go +++ b/registrars.go @@ -7,8 +7,8 @@ import ( "time" ) -// RegisterLazyCreatorToContainer Registers a lazily initialized value to the given container using a `Creator[T]` interface -func RegisterLazyCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T], key ...KeyStringer) { +// RegisterCreatorToContainer Registers a lazily initialized value to the given container using a `Creator[T]` interface +func RegisterCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T], key ...KeyStringer) { if creator == nil { panic(nilVal[T]()) } @@ -22,14 +22,14 @@ func RegisterLazyCreatorToContainer[T any](con *Container, lifetime Lifetime, cr addResolver[T](con, e, key...) } -// RegisterLazyCreator Registers a lazily initialized value using a `Creator[T]` interface -func RegisterLazyCreator[T any](lifetime Lifetime, creator Creator[T], key ...KeyStringer) { - RegisterLazyCreatorToContainer[T](DefaultContainer, lifetime, creator, key...) +// RegisterCreator Registers a lazily initialized value using a `Creator[T]` interface +func RegisterCreator[T any](lifetime Lifetime, creator Creator[T], key ...KeyStringer) { + RegisterCreatorToContainer[T](DefaultContainer, lifetime, creator, key...) } -// RegisterEagerSingletonToContainer Registers an eagerly instantiated singleton value to the given container. +// RegisterSingletonToContainer Registers an eagerly instantiated singleton value to the given container. // To register an eagerly instantiated scoped value use [ProvideScopedValueToContainer] -func RegisterEagerSingletonToContainer[T comparable](con *Container, impl T, key ...KeyStringer) { +func RegisterSingletonToContainer[T comparable](con *Container, impl T, key ...KeyStringer) { if isNil[T](impl) { panic(nilVal[T]()) } @@ -47,14 +47,14 @@ func RegisterEagerSingletonToContainer[T comparable](con *Container, impl T, key addResolver[T](con, e, key...) } -// RegisterEagerSingleton Registers an eagerly instantiated singleton value +// RegisterSingleton Registers an eagerly instantiated singleton value // To register an eagerly instantiated scoped value use [ProvideScopedValue] -func RegisterEagerSingleton[T comparable](impl T, key ...KeyStringer) { - RegisterEagerSingletonToContainer[T](DefaultContainer, impl, key...) +func RegisterSingleton[T comparable](impl T, key ...KeyStringer) { + RegisterSingletonToContainer[T](DefaultContainer, impl, key...) } -// RegisterLazyFuncToContainer Registers a lazily initialized value to the given container using an `Initializer[T]` function signature -func RegisterLazyFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { +// RegisterFuncToContainer Registers a lazily initialized value to the given container using an `Initializer[T]` function signature +func RegisterFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { if initializer == nil { panic(nilVal[T]()) } @@ -68,9 +68,9 @@ func RegisterLazyFuncToContainer[T any](con *Container, lifetime Lifetime, initi addResolver[T](con, e, key...) } -// RegisterLazyFunc Registers a lazily initialized value using an `Initializer[T]` function signature -func RegisterLazyFunc[T any](lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { - RegisterLazyFuncToContainer(DefaultContainer, lifetime, initializer, key...) +// RegisterFunc Registers a lazily initialized value using an `Initializer[T]` function signature +func RegisterFunc[T any](lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { + RegisterFuncToContainer(DefaultContainer, lifetime, initializer, key...) } // RegisterAliasToContainer Registers an interface type to a concrete implementation in the given container. @@ -92,11 +92,11 @@ func RegisterAlias[TInterface, TImpl any]() { RegisterAliasToContainer[TInterface, TImpl](DefaultContainer) } -// RegisterPlaceHolderToContainer registers a future value with Scoped lifetime to the given container. +// RegisterPlaceholderToContainer registers a future value with Scoped lifetime to the given container. // This value will be injected in runtime using the [ProvideScopedValue] function. // Resolving objects which depend on this value will panic if the value has not been provided. // Placeholder with the same type and key can be registered only once. -func RegisterPlaceHolderToContainer[T comparable](con *Container, key ...KeyStringer) { +func RegisterPlaceholderToContainer[T comparable](con *Container, key ...KeyStringer) { e := serviceResolverImpl[T]{ resolverMetadata: resolverMetadata{ lifetime: Scoped, @@ -105,17 +105,17 @@ func RegisterPlaceHolderToContainer[T comparable](con *Container, key ...KeyStri addResolver[T](con, e, key...) } -// RegisterPlaceHolder registers a future value with Scoped lifetime. +// RegisterPlaceholder registers a future value with Scoped lifetime. // This value will be injected in runtime using the [ProvideScopedValue] function. // Resolving objects which depend on this value will panic if the value has not been provided. // Placeholder with the same type and key can be registered only once. -func RegisterPlaceHolder[T comparable](key ...KeyStringer) { - RegisterPlaceHolderToContainer[T](DefaultContainer, key...) +func RegisterPlaceholder[T comparable](key ...KeyStringer) { + RegisterPlaceholderToContainer[T](DefaultContainer, key...) } // ProvideScopedValueToContainer injects a concrete value into the given context. // This value will be available only to the given container. And the container can only resolve this value if -// it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceHolderToContainer] function for more info. +// it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholderToContainer] function for more info. func ProvideScopedValueToContainer[T comparable](con *Container, ctx context.Context, value T, key ...KeyStringer) context.Context { concreteValue := &concrete{ value: value, @@ -133,7 +133,7 @@ func ProvideScopedValueToContainer[T comparable](con *Container, ctx context.Con // ProvideScopedValue injects a concrete value into the given context. // This value will be available only to the default container. And the container can only resolve this value if -// it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceHolder] function for more info. +// it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholder] function for more info. func ProvideScopedValue[T comparable](ctx context.Context, value T, key ...KeyStringer) context.Context { return ProvideScopedValueToContainer[T](DefaultContainer, ctx, value, key...) } diff --git a/registrars_placeholder_test.go b/registrars_placeholder_test.go index 11d53a1..ea28c5f 100644 --- a/registrars_placeholder_test.go +++ b/registrars_placeholder_test.go @@ -13,7 +13,7 @@ func TestPlaceHolder_HappyPath(t *testing.T) { clearAll() //register a placeHolder - RegisterPlaceHolder[*m.Trader]() + RegisterPlaceholder[*m.Trader]() //get the placeHolder value would failed assert2.PanicsWithError(t, assert2.ErrorStartsWith("No value has been provided for this placeholder"), func() { @@ -59,7 +59,7 @@ func TestPlaceHolder_ProvideValueBeforeRegistering(t *testing.T) { }) //register a matching placeHolder - RegisterPlaceHolder[*m.Trader]() + RegisterPlaceholder[*m.Trader]() //get the placeHolder value would success trader, _ := Get[*m.Trader](ctx) @@ -71,24 +71,24 @@ func TestPlaceHolder_OverrideRealResolver(t *testing.T) { clearAll() //register a real resolver - RegisterEagerSingleton(&m.Trader{Name: "Mary"}, "module1") + RegisterSingleton(&m.Trader{Name: "Mary"}, "module1") //register a placeHolder to override the real resolver should failed assert2.PanicsWithError(t, assert2.ErrorContains("has already been registered"), func() { - RegisterPlaceHolder[*m.Trader]("module1") + RegisterPlaceholder[*m.Trader]("module1") }) //register 2 time a placeHolder should failed - RegisterPlaceHolder[*m.Trader]("module2") + RegisterPlaceholder[*m.Trader]("module2") assert2.PanicsWithError(t, assert2.ErrorContains("has already been registered"), func() { - RegisterPlaceHolder[*m.Trader]("module2") + RegisterPlaceholder[*m.Trader]("module2") }) } func TestPlaceHolder_OverridePlaceHolder(t *testing.T) { clearAll() //register a placeHolder - RegisterPlaceHolder[*m.Trader]("module2") + RegisterPlaceholder[*m.Trader]("module2") //Provide the value to the placeHolder ctx := ProvideScopedValue[*m.Trader](context.Background(), &m.Trader{Name: "John"}, "module2") @@ -107,7 +107,7 @@ func TestPlaceHolder_OverridePlaceHolder(t *testing.T) { assert.Equal(t, "David", traders[0].Name) //Register a real resolver should override the placeHolder resolver - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.Trader, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.Trader, context.Context) { return &m.Trader{Name: "Mary"}, ctx }, "module2") @@ -137,10 +137,10 @@ func TestPlaceHolder_OverridePlaceHolder(t *testing.T) { // placeholder value of a module is not accessible from other module func TestPlaceHolder_PerModule(t *testing.T) { con1 := NewContainer() - RegisterPlaceHolderToContainer[*m.Trader](con1) + RegisterPlaceholderToContainer[*m.Trader](con1) con2 := NewContainer() - RegisterPlaceHolderToContainer[*m.Trader](con2) + RegisterPlaceholderToContainer[*m.Trader](con2) ctx := ProvideScopedValueToContainer(con1, context.Background(), &m.Trader{Name: "John"}) trader, ctx := GetFromContainer[*m.Trader](con1, ctx) diff --git a/validate_test.go b/validate_test.go index 20dfefe..6a22366 100644 --- a/validate_test.go +++ b/validate_test.go @@ -13,7 +13,7 @@ func TestValidate_CircularDepsUniformLifetype(t *testing.T) { for _, lt := range types { t.Run("Direct circular "+lt.String()+" (1 calls 1)", func(t *testing.T) { clearAll() - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService1, context.Context) { _, ctx = Get[*m.DisposableService1](ctx) //1 calls 1 return &m.DisposableService1{Name: "1"}, ctx }) @@ -21,15 +21,15 @@ func TestValidate_CircularDepsUniformLifetype(t *testing.T) { }) t.Run("Indirect circular "+lt.String()+" (1 calls 2 calls 3 calls 1)", func(t *testing.T) { clearAll() - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService1, context.Context) { _, ctx = Get[*m.DisposableService2](ctx) //1 calls 2 return &m.DisposableService1{Name: "1"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService2, context.Context) { _, ctx = Get[*m.DisposableService3](ctx) //2 calls 3 return &m.DisposableService2{Name: "2"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService3, context.Context) { _, ctx = Get[*m.DisposableService1](ctx) //3 calls 1 return &m.DisposableService3{Name: "3"}, ctx }) @@ -37,19 +37,19 @@ func TestValidate_CircularDepsUniformLifetype(t *testing.T) { }) t.Run("Middle circular "+lt.String()+" (1 calls 2 calls 3 calls 4 calls 2)", func(t *testing.T) { clearAll() - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService1, context.Context) { _, ctx = Get[*m.DisposableService2](ctx) //1 calls 2 return &m.DisposableService1{Name: "1"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService2, context.Context) { _, ctx = Get[*m.DisposableService3](ctx) //2 calls 3 return &m.DisposableService2{Name: "2"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService3, context.Context) { _, ctx = Get[*m.DisposableService4](ctx) //3 calls 4 return &m.DisposableService3{Name: "3"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService4, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService4, context.Context) { _, ctx = Get[*m.DisposableService2](ctx) //4 calls 2 return &m.DisposableService4{Name: "4"}, ctx }) @@ -57,25 +57,25 @@ func TestValidate_CircularDepsUniformLifetype(t *testing.T) { }) t.Run("circular on complex tree "+lt.String()+"", func(t *testing.T) { clearAll() - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService1, context.Context) { _, ctx = Get[*m.DisposableService2](ctx) //1 calls 2 _, ctx = Get[*m.DisposableService3](ctx) //1 calls 3 return &m.DisposableService1{Name: "1"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService2, context.Context) { _, ctx = Get[*m.DisposableService4](ctx) //2 calls 4 _, ctx = Get[*m.DisposableService5](ctx) //2 calls 5 return &m.DisposableService2{Name: "2"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService3, context.Context) { _, ctx = Get[*m.DisposableService4](ctx) //3 calls 4 return &m.DisposableService3{Name: "3"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService4, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService4, context.Context) { _, ctx = Get[*m.DisposableService5](ctx) //4 calls 5 return &m.DisposableService4{Name: "4"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService5, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService5, context.Context) { _, ctx = Get[*m.DisposableService3](ctx) //5 calls 3 => circular here: 5->3->4->5 return &m.DisposableService5{Name: "5"}, ctx }) @@ -83,38 +83,38 @@ func TestValidate_CircularDepsUniformLifetype(t *testing.T) { }) t.Run("fake circular top down "+lt.String()+": (1 calls 2 (x2) calls 3 calls 4, 2 calls 4)", func(t *testing.T) { clearAll() - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService1, context.Context) { _, ctx = Get[*m.DisposableService2](ctx) //1 calls 2 _, ctx = Get[*m.DisposableService2](ctx) //1 calls 2 again return &m.DisposableService1{Name: "1"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService2, context.Context) { _, ctx = Get[*m.DisposableService3](ctx) //2 calls 3 _, ctx = Get[*m.DisposableService4](ctx) //2 calls 4 return &m.DisposableService2{Name: "2"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService3, context.Context) { _, ctx = Get[*m.DisposableService4](ctx) //3 calls 4 _, ctx = Get[*m.DisposableService4](ctx) //3 calls 4 return &m.DisposableService3{Name: "3"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService4, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService4, context.Context) { return &m.DisposableService4{Name: "4"}, ctx }) assert.NotPanics(t, Validate) }) t.Run("fake circular sibling "+lt.String()+": 1 calls 2 & 3; 2 calls 3)", func(t *testing.T) { clearAll() - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService1, context.Context) { _, ctx = Get[*m.DisposableService2](ctx) //1 calls 2 _, ctx = Get[*m.DisposableService3](ctx) //1 calls 3 return &m.DisposableService1{Name: "1"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService2, context.Context) { _, ctx = Get[*m.DisposableService3](ctx) //2 calls 3 return &m.DisposableService2{Name: "2"}, ctx }) - RegisterLazyFunc(lt, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterFunc(lt, func(ctx context.Context) (*m.DisposableService3, context.Context) { return &m.DisposableService3{Name: "3"}, ctx }) assert.NotPanics(t, Validate) @@ -125,24 +125,24 @@ func TestValidate_CircularDepsUniformLifetype(t *testing.T) { func TestValidate_CircularMixedLifetype(t *testing.T) { clearAll() - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { _, ctx = Get[*m.DisposableService4](ctx) //2 calls 4 _, ctx = Get[*m.DisposableService5](ctx) //2 calls 5 return &m.DisposableService2{Name: "2"}, ctx }) - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService3, context.Context) { _, ctx = Get[*m.DisposableService4](ctx) //3 calls 4 return &m.DisposableService3{Name: "3"}, ctx }) - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService4, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService4, context.Context) { _, ctx = Get[*m.DisposableService5](ctx) //4 calls 5 return &m.DisposableService4{Name: "4"}, ctx }) - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService5, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService5, context.Context) { _, ctx = Get[*m.DisposableService3](ctx) //5 calls 3 => circular here: 5->3->4->5 return &m.DisposableService5{Name: "5"}, ctx }) - RegisterLazyFunc(Transient, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(Transient, func(ctx context.Context) (*m.DisposableService1, context.Context) { _, ctx = Get[*m.DisposableService2](ctx) //1 calls 2 _, ctx = Get[*m.DisposableService3](ctx) //1 calls 3 return &m.DisposableService1{Name: "1"}, ctx @@ -155,10 +155,10 @@ func TestValidate_CircularMixedLifetype(t *testing.T) { func TestValidate_LifetimeAlignment_SingletonCallsScoped(t *testing.T) { con := NewContainer() - RegisterLazyFuncToContainer(con, Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFuncToContainer(con, Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { return &m.DisposableService2{Name: "2"}, ctx }) - RegisterLazyFuncToContainer(con, Singleton, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFuncToContainer(con, Singleton, func(ctx context.Context) (*m.DisposableService1, context.Context) { _, ctx = GetFromContainer[*m.DisposableService2](con, ctx) //1 depends on 2 return &m.DisposableService1{Name: "1"}, ctx }) @@ -166,26 +166,26 @@ func TestValidate_LifetimeAlignment_SingletonCallsScoped(t *testing.T) { } func TestValidate_LifetimeAlignment_ScopedCallsTransient(t *testing.T) { con := NewContainer() - RegisterLazyFuncToContainer(con, Scoped, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFuncToContainer(con, Scoped, func(ctx context.Context) (*m.DisposableService1, context.Context) { _, ctx = GetFromContainer[*m.DisposableService2](con, ctx) //1 depends on 2 return &m.DisposableService1{Name: "1"}, ctx }) - RegisterLazyFuncToContainer(con, Transient, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFuncToContainer(con, Transient, func(ctx context.Context) (*m.DisposableService2, context.Context) { return &m.DisposableService2{Name: "2"}, ctx }) assert2.PanicsWithError(t, assert2.ErrorStartsWith("detect lifetime misalignment"), con.Validate) } func TestValidate_LifetimeAlignment_SingletonCallsTransient(t *testing.T) { con := NewContainer() - RegisterLazyFuncToContainer(con, Singleton, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFuncToContainer(con, Singleton, func(ctx context.Context) (*m.DisposableService1, context.Context) { _, ctx = GetFromContainer[*m.DisposableService2](con, ctx) //1 depends on 2 return &m.DisposableService1{Name: "1"}, ctx }) - RegisterLazyFuncToContainer(con, Singleton, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFuncToContainer(con, Singleton, func(ctx context.Context) (*m.DisposableService2, context.Context) { _, ctx = GetFromContainer[*m.DisposableService3](con, ctx) //2 depends on 3 return &m.DisposableService2{Name: "2"}, ctx }) - RegisterLazyFuncToContainer(con, Transient, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterFuncToContainer(con, Transient, func(ctx context.Context) (*m.DisposableService3, context.Context) { return &m.DisposableService3{Name: "3"}, ctx }) assert2.PanicsWithError(t, assert2.ErrorStartsWith("detect lifetime misalignment"), con.Validate) @@ -193,15 +193,15 @@ func TestValidate_LifetimeAlignment_SingletonCallsTransient(t *testing.T) { func TestValidate_MissingDependency(t *testing.T) { clearAll() - RegisterLazyFunc(Transient, func(ctx context.Context) (*m.DisposableService1, context.Context) { + RegisterFunc(Transient, func(ctx context.Context) (*m.DisposableService1, context.Context) { _, ctx = Get[*m.DisposableService2](ctx) //1 depends on 2 return &m.DisposableService1{Name: "1"}, ctx }) - RegisterLazyFunc(Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { _, ctx = Get[*m.DisposableService3](ctx) //2 depends on 3 return &m.DisposableService2{Name: "2"}, ctx }) - RegisterLazyFunc(Singleton, func(ctx context.Context) (*m.DisposableService3, context.Context) { + RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService3, context.Context) { _, ctx = Get[*m.DisposableService4](ctx) //3 depends on 4 return &m.DisposableService3{Name: "3"}, ctx }) @@ -211,20 +211,20 @@ func TestValidate_MissingDependency(t *testing.T) { func TestValidate_WithPlaceHolder(t *testing.T) { con := NewContainer() - RegisterPlaceHolderToContainer[*m.Trader](con) + RegisterPlaceholderToContainer[*m.Trader](con) assert.NotPanics(t, con.Validate) } func TestValidate_WithPlaceHolderInterface(t *testing.T) { con := NewContainer() - RegisterPlaceHolderToContainer[m.IPerson](con) + RegisterPlaceholderToContainer[m.IPerson](con) assert.NotPanics(t, con.Validate) } func TestValidate_DisableValidation(t *testing.T) { con := NewContainer() - RegisterPlaceHolderToContainer[*m.Trader](con) - RegisterLazyFuncToContainer(con, Singleton, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterPlaceholderToContainer[*m.Trader](con) + RegisterFuncToContainer(con, Singleton, func(ctx context.Context) (*m.Broker, context.Context) { _, ctx = GetFromContainer[*m.Trader](con, ctx) return &m.Broker{Name: "John"}, ctx }) From 6f8e2a64d39adfb4219f4901577a06e8a459c051 Mon Sep 17 00:00:00 2001 From: Firas Darwish Date: Fri, 15 Nov 2024 14:09:09 +0300 Subject: [PATCH 02/12] reorder registration funcs --- container_registerers.go | 42 ++++++++++ default_container_registerers.go | 40 +++++++++ internal_registerers.go | 89 ++++++++++++++++++++ registrars.go | 139 ------------------------------- 4 files changed, 171 insertions(+), 139 deletions(-) create mode 100644 container_registerers.go create mode 100644 default_container_registerers.go create mode 100644 internal_registerers.go delete mode 100644 registrars.go diff --git a/container_registerers.go b/container_registerers.go new file mode 100644 index 0000000..5d4b843 --- /dev/null +++ b/container_registerers.go @@ -0,0 +1,42 @@ +package ore + +import ( + "context" +) + +// RegisterCreatorToContainer Registers a lazily initialized value to the given container using a `Creator[T]` interface +func RegisterCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T], key ...KeyStringer) { + registerCreatorToContainer(con, lifetime, creator, key...) +} + +// RegisterSingletonToContainer Registers an eagerly instantiated singleton value to the given container. +// To register an eagerly instantiated scoped value use [ProvideScopedValueToContainer] +func RegisterSingletonToContainer[T comparable](con *Container, impl T, key ...KeyStringer) { + registerSingletonToContainer(con, impl, key...) +} + +// RegisterFuncToContainer Registers a lazily initialized value to the given container using an `Initializer[T]` function signature +func RegisterFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { + registerFuncToContainer(con, lifetime, initializer, key...) +} + +// RegisterAliasToContainer Registers an interface type to a concrete implementation in the given container. +// Allowing you to register the concrete implementation to the container and later get the interface from it. +func RegisterAliasToContainer[TInterface, TImpl any](con *Container) { + registerAliasToContainer[TInterface, TImpl](con) +} + +// RegisterPlaceholderToContainer registers a future value with Scoped lifetime to the given container. +// This value will be injected in runtime using the [ProvideScopedValue] function. +// Resolving objects which depend on this value will panic if the value has not been provided. +// Placeholder with the same type and key can be registered only once. +func RegisterPlaceholderToContainer[T comparable](con *Container, key ...KeyStringer) { + registerPlaceholderToContainer[T](con, key...) +} + +// ProvideScopedValueToContainer injects a concrete value into the given context. +// This value will be available only to the given container. And the container can only resolve this value if +// it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholderToContainer] function for more info. +func ProvideScopedValueToContainer[T comparable](con *Container, ctx context.Context, value T, key ...KeyStringer) context.Context { + return provideScopedValueToContainer(con, ctx, value, key...) +} diff --git a/default_container_registerers.go b/default_container_registerers.go new file mode 100644 index 0000000..d101139 --- /dev/null +++ b/default_container_registerers.go @@ -0,0 +1,40 @@ +package ore + +import "context" + +// RegisterCreator Registers a lazily initialized value using a `Creator[T]` interface +func RegisterCreator[T any](lifetime Lifetime, creator Creator[T], key ...KeyStringer) { + registerCreatorToContainer[T](DefaultContainer, lifetime, creator, key...) +} + +// RegisterSingleton Registers an eagerly instantiated singleton value +// To register an eagerly instantiated scoped value use [ProvideScopedValue] +func RegisterSingleton[T comparable](impl T, key ...KeyStringer) { + registerSingletonToContainer[T](DefaultContainer, impl, key...) +} + +// RegisterFunc Registers a lazily initialized value using an `Initializer[T]` function signature +func RegisterFunc[T any](lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { + registerFuncToContainer(DefaultContainer, lifetime, initializer, key...) +} + +// RegisterAlias Registers an interface type to a concrete implementation. +// Allowing you to register the concrete implementation to the default container and later get the interface from it. +func RegisterAlias[TInterface, TImpl any]() { + registerAliasToContainer[TInterface, TImpl](DefaultContainer) +} + +// RegisterPlaceholder registers a future value with Scoped lifetime. +// This value will be injected in runtime using the [ProvideScopedValue] function. +// Resolving objects which depend on this value will panic if the value has not been provided. +// Placeholder with the same type and key can be registered only once. +func RegisterPlaceholder[T comparable](key ...KeyStringer) { + registerPlaceholderToContainer[T](DefaultContainer, key...) +} + +// ProvideScopedValue injects a concrete value into the given context. +// This value will be available only to the default container. And the container can only resolve this value if +// it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholder] function for more info. +func ProvideScopedValue[T comparable](ctx context.Context, value T, key ...KeyStringer) context.Context { + return provideScopedValueToContainer(DefaultContainer, ctx, value, key...) +} diff --git a/internal_registerers.go b/internal_registerers.go new file mode 100644 index 0000000..8296ca7 --- /dev/null +++ b/internal_registerers.go @@ -0,0 +1,89 @@ +package ore + +import ( + "context" + "fmt" + "reflect" + "time" +) + +func registerCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T], key ...KeyStringer) { + if creator == nil { + panic(nilVal[T]()) + } + + e := serviceResolverImpl[T]{ + resolverMetadata: resolverMetadata{ + lifetime: lifetime, + }, + creatorInstance: creator, + } + addResolver[T](con, e, key...) +} + +func registerSingletonToContainer[T comparable](con *Container, impl T, key ...KeyStringer) { + if isNil[T](impl) { + panic(nilVal[T]()) + } + + e := serviceResolverImpl[T]{ + resolverMetadata: resolverMetadata{ + lifetime: Singleton, + }, + singletonConcrete: &concrete{ + value: impl, + lifetime: Singleton, + invocationTime: time.Now(), + }, + } + addResolver[T](con, e, key...) +} + +func registerFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { + if initializer == nil { + panic(nilVal[T]()) + } + + e := serviceResolverImpl[T]{ + resolverMetadata: resolverMetadata{ + lifetime: lifetime, + }, + anonymousInitializer: &initializer, + } + addResolver[T](con, e, key...) +} + +func registerAliasToContainer[TInterface, TImpl any](con *Container) { + interfaceType := reflect.TypeFor[TInterface]() + implType := reflect.TypeFor[TImpl]() + + if !implType.Implements(interfaceType) { + panic(fmt.Errorf("%s does not implements %s", implType, interfaceType)) + } + + addAliases[TInterface, TImpl](con) +} + +func registerPlaceholderToContainer[T comparable](con *Container, key ...KeyStringer) { + e := serviceResolverImpl[T]{ + resolverMetadata: resolverMetadata{ + lifetime: Scoped, + }, + } + addResolver[T](con, e, key...) +} + +func provideScopedValueToContainer[T comparable](con *Container, ctx context.Context, value T, key ...KeyStringer) context.Context { + concreteValue := &concrete{ + value: value, + lifetime: Scoped, + invocationTime: time.Now(), + invocationLevel: 0, + } + id := contextKey{ + containerID: con.containerID, + typeID: typeIdentifier[T](key...), + resolverID: placeHolderResolverID, + } + return addScopedConcreteToContext(ctx, id, concreteValue) +} diff --git a/registrars.go b/registrars.go deleted file mode 100644 index 7e3a258..0000000 --- a/registrars.go +++ /dev/null @@ -1,139 +0,0 @@ -package ore - -import ( - "context" - "fmt" - "reflect" - "time" -) - -// RegisterCreatorToContainer Registers a lazily initialized value to the given container using a `Creator[T]` interface -func RegisterCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T], key ...KeyStringer) { - if creator == nil { - panic(nilVal[T]()) - } - - e := serviceResolverImpl[T]{ - resolverMetadata: resolverMetadata{ - lifetime: lifetime, - }, - creatorInstance: creator, - } - addResolver[T](con, e, key...) -} - -// RegisterCreator Registers a lazily initialized value using a `Creator[T]` interface -func RegisterCreator[T any](lifetime Lifetime, creator Creator[T], key ...KeyStringer) { - RegisterCreatorToContainer[T](DefaultContainer, lifetime, creator, key...) -} - -// RegisterSingletonToContainer Registers an eagerly instantiated singleton value to the given container. -// To register an eagerly instantiated scoped value use [ProvideScopedValueToContainer] -func RegisterSingletonToContainer[T comparable](con *Container, impl T, key ...KeyStringer) { - if isNil[T](impl) { - panic(nilVal[T]()) - } - - e := serviceResolverImpl[T]{ - resolverMetadata: resolverMetadata{ - lifetime: Singleton, - }, - singletonConcrete: &concrete{ - value: impl, - lifetime: Singleton, - invocationTime: time.Now(), - }, - } - addResolver[T](con, e, key...) -} - -// RegisterSingleton Registers an eagerly instantiated singleton value -// To register an eagerly instantiated scoped value use [ProvideScopedValue] -func RegisterSingleton[T comparable](impl T, key ...KeyStringer) { - RegisterSingletonToContainer[T](DefaultContainer, impl, key...) -} - -// RegisterFuncToContainer Registers a lazily initialized value to the given container using an `Initializer[T]` function signature -func RegisterFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { - if initializer == nil { - panic(nilVal[T]()) - } - - e := serviceResolverImpl[T]{ - resolverMetadata: resolverMetadata{ - lifetime: lifetime, - }, - anonymousInitializer: &initializer, - } - addResolver[T](con, e, key...) -} - -// RegisterFunc Registers a lazily initialized value using an `Initializer[T]` function signature -func RegisterFunc[T any](lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { - RegisterFuncToContainer(DefaultContainer, lifetime, initializer, key...) -} - -// RegisterAliasToContainer Registers an interface type to a concrete implementation in the given container. -// Allowing you to register the concrete implementation to the container and later get the interface from it. -func RegisterAliasToContainer[TInterface, TImpl any](con *Container) { - interfaceType := reflect.TypeFor[TInterface]() - implType := reflect.TypeFor[TImpl]() - - if !implType.Implements(interfaceType) { - panic(fmt.Errorf("%s does not implements %s", implType, interfaceType)) - } - - addAliases[TInterface, TImpl](con) -} - -// RegisterAlias Registers an interface type to a concrete implementation. -// Allowing you to register the concrete implementation to the default container and later get the interface from it. -func RegisterAlias[TInterface, TImpl any]() { - RegisterAliasToContainer[TInterface, TImpl](DefaultContainer) -} - -// RegisterPlaceholderToContainer registers a future value with Scoped lifetime to the given container. -// This value will be injected in runtime using the [ProvideScopedValue] function. -// Resolving objects which depend on this value will panic if the value has not been provided. -// Placeholder with the same type and key can be registered only once. -func RegisterPlaceholderToContainer[T comparable](con *Container, key ...KeyStringer) { - e := serviceResolverImpl[T]{ - resolverMetadata: resolverMetadata{ - lifetime: Scoped, - }, - } - addResolver[T](con, e, key...) -} - -// RegisterPlaceholder registers a future value with Scoped lifetime. -// This value will be injected in runtime using the [ProvideScopedValue] function. -// Resolving objects which depend on this value will panic if the value has not been provided. -// Placeholder with the same type and key can be registered only once. -func RegisterPlaceholder[T comparable](key ...KeyStringer) { - RegisterPlaceholderToContainer[T](DefaultContainer, key...) -} - -// ProvideScopedValueToContainer injects a concrete value into the given context. -// This value will be available only to the given container. And the container can only resolve this value if -// it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholderToContainer] function for more info. -func ProvideScopedValueToContainer[T comparable](con *Container, ctx context.Context, value T, key ...KeyStringer) context.Context { - concreteValue := &concrete{ - value: value, - lifetime: Scoped, - invocationTime: time.Now(), - invocationLevel: 0, - } - id := contextKey{ - containerID: con.containerID, - typeID: typeIdentifier[T](key...), - resolverID: placeHolderResolverID, - } - return addScopedConcreteToContext(ctx, id, concreteValue) -} - -// ProvideScopedValue injects a concrete value into the given context. -// This value will be available only to the default container. And the container can only resolve this value if -// it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholder] function for more info. -func ProvideScopedValue[T comparable](ctx context.Context, value T, key ...KeyStringer) context.Context { - return ProvideScopedValueToContainer[T](DefaultContainer, ctx, value, key...) -} From 9e0150f1d668dd67930b4b19478d6d18d62e146f Mon Sep 17 00:00:00 2001 From: Firas Darwish Date: Fri, 15 Nov 2024 14:18:31 +0300 Subject: [PATCH 03/12] separate raw & keyed funcs --- alias_test.go | 18 ++++---- container_keyed_registerers.go | 43 +++++++++++++++++++ ...ers.go => container_unkeyed_registerers.go | 26 +++++------ creator_test.go | 8 ++-- default_container_keyed_registerers.go | 40 +++++++++++++++++ ...> default_container_unkeyed_registerers.go | 20 ++++----- eager_singleton_test.go | 8 ++-- get_list_test.go | 8 ++-- get_test.go | 6 +-- initializer_test.go | 8 ++-- registrars_placeholder_test.go | 18 ++++---- 11 files changed, 140 insertions(+), 63 deletions(-) create mode 100644 container_keyed_registerers.go rename container_registerers.go => container_unkeyed_registerers.go (63%) create mode 100644 default_container_keyed_registerers.go rename default_container_registerers.go => default_container_unkeyed_registerers.go (81%) diff --git a/alias_test.go b/alias_test.go index 52c0088..9c632e0 100644 --- a/alias_test.go +++ b/alias_test.go @@ -58,13 +58,13 @@ func TestAliasOfAliasIsNotAllow(t *testing.T) { func TestAliasWithDifferentScope(t *testing.T) { clearAll() module := "TestGetInterfaceAliasWithDifferentScope" - RegisterFunc(Transient, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterKeyedFunc(Transient, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "Transient"}, ctx }, module) - RegisterFunc(Singleton, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterKeyedFunc(Singleton, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "Singleton"}, ctx }, module) - RegisterFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterKeyedFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "Scoped"}, ctx }, module) RegisterAlias[m.IPerson, *m.Broker]() //link m.IPerson to *m.Broker @@ -80,24 +80,24 @@ func TestAliasWithDifferentScope(t *testing.T) { func TestAliasIsScopedByKeys(t *testing.T) { clearAll() - RegisterFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterKeyedFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "Peter1"}, ctx }, "module1") - RegisterFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterKeyedFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "John1"}, ctx }, "module1") - RegisterFunc(Scoped, func(ctx context.Context) (*m.Trader, context.Context) { + RegisterKeyedFunc(Scoped, func(ctx context.Context) (*m.Trader, context.Context) { return &m.Trader{Name: "Mary1"}, ctx }, "module1") - RegisterFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { + RegisterKeyedFunc(Scoped, func(ctx context.Context) (*m.Broker, context.Context) { return &m.Broker{Name: "John2"}, ctx }, "module2") - RegisterFunc(Scoped, func(ctx context.Context) (*m.Trader, context.Context) { + RegisterKeyedFunc(Scoped, func(ctx context.Context) (*m.Trader, context.Context) { return &m.Trader{Name: "Mary2"}, ctx }, "module2") - RegisterFunc(Scoped, func(ctx context.Context) (*m.Trader, context.Context) { + RegisterKeyedFunc(Scoped, func(ctx context.Context) (*m.Trader, context.Context) { return &m.Trader{Name: "Mary3"}, ctx }, "module3") diff --git a/container_keyed_registerers.go b/container_keyed_registerers.go new file mode 100644 index 0000000..9e7f3cc --- /dev/null +++ b/container_keyed_registerers.go @@ -0,0 +1,43 @@ +package ore + +import ( + "context" +) + +// RegisterKeyedCreatorToContainer Registers a lazily initialized value to the given container using a `Creator[T]` interface +func RegisterKeyedCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T], key ...KeyStringer) { + registerCreatorToContainer(con, lifetime, creator, key...) +} + +// RegisterKeyedSingletonToContainer Registers an eagerly instantiated singleton value to the given container. +// To register an eagerly instantiated scoped value use [ProvideScopedValueToContainer] +func RegisterKeyedSingletonToContainer[T comparable](con *Container, impl T, key ...KeyStringer) { + registerSingletonToContainer(con, impl, key...) +} + +// RegisterKeyedFuncToContainer Registers a lazily initialized value to the given container using an `Initializer[T]` function signature +func RegisterKeyedFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { + registerFuncToContainer(con, lifetime, initializer, key...) +} + +// TODO move to sep file +// RegisterAliasToContainer Registers an interface type to a concrete implementation in the given container. +// Allowing you to register the concrete implementation to the container and later get the interface from it. +func RegisterAliasToContainer[TInterface, TImpl any](con *Container) { + registerAliasToContainer[TInterface, TImpl](con) +} + +// RegisterKeyedPlaceholderToContainer registers a future value with Scoped lifetime to the given container. +// This value will be injected in runtime using the [ProvideScopedValue] function. +// Resolving objects which depend on this value will panic if the value has not been provided. +// Placeholder with the same type and key can be registered only once. +func RegisterKeyedPlaceholderToContainer[T comparable](con *Container, key ...KeyStringer) { + registerPlaceholderToContainer[T](con, key...) +} + +// ProvideKeyedScopedValueToContainer injects a concrete value into the given context. +// This value will be available only to the given container. And the container can only resolve this value if +// it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholderToContainer] function for more info. +func ProvideKeyedScopedValueToContainer[T comparable](con *Container, ctx context.Context, value T, key ...KeyStringer) context.Context { + return provideScopedValueToContainer(con, ctx, value, key...) +} diff --git a/container_registerers.go b/container_unkeyed_registerers.go similarity index 63% rename from container_registerers.go rename to container_unkeyed_registerers.go index 5d4b843..7cf3628 100644 --- a/container_registerers.go +++ b/container_unkeyed_registerers.go @@ -5,38 +5,32 @@ import ( ) // RegisterCreatorToContainer Registers a lazily initialized value to the given container using a `Creator[T]` interface -func RegisterCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T], key ...KeyStringer) { - registerCreatorToContainer(con, lifetime, creator, key...) +func RegisterCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T]) { + registerCreatorToContainer(con, lifetime, creator) } // RegisterSingletonToContainer Registers an eagerly instantiated singleton value to the given container. // To register an eagerly instantiated scoped value use [ProvideScopedValueToContainer] -func RegisterSingletonToContainer[T comparable](con *Container, impl T, key ...KeyStringer) { - registerSingletonToContainer(con, impl, key...) +func RegisterSingletonToContainer[T comparable](con *Container, impl T) { + registerSingletonToContainer(con, impl) } // RegisterFuncToContainer Registers a lazily initialized value to the given container using an `Initializer[T]` function signature -func RegisterFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { - registerFuncToContainer(con, lifetime, initializer, key...) -} - -// RegisterAliasToContainer Registers an interface type to a concrete implementation in the given container. -// Allowing you to register the concrete implementation to the container and later get the interface from it. -func RegisterAliasToContainer[TInterface, TImpl any](con *Container) { - registerAliasToContainer[TInterface, TImpl](con) +func RegisterFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T]) { + registerFuncToContainer(con, lifetime, initializer) } // RegisterPlaceholderToContainer registers a future value with Scoped lifetime to the given container. // This value will be injected in runtime using the [ProvideScopedValue] function. // Resolving objects which depend on this value will panic if the value has not been provided. // Placeholder with the same type and key can be registered only once. -func RegisterPlaceholderToContainer[T comparable](con *Container, key ...KeyStringer) { - registerPlaceholderToContainer[T](con, key...) +func RegisterPlaceholderToContainer[T comparable](con *Container) { + registerPlaceholderToContainer[T](con) } // ProvideScopedValueToContainer injects a concrete value into the given context. // This value will be available only to the given container. And the container can only resolve this value if // it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholderToContainer] function for more info. -func ProvideScopedValueToContainer[T comparable](con *Container, ctx context.Context, value T, key ...KeyStringer) context.Context { - return provideScopedValueToContainer(con, ctx, value, key...) +func ProvideScopedValueToContainer[T comparable](con *Container, ctx context.Context, value T) context.Context { + return provideScopedValueToContainer(con, ctx, value) } diff --git a/creator_test.go b/creator_test.go index 693c9bc..67315d4 100644 --- a/creator_test.go +++ b/creator_test.go @@ -69,9 +69,9 @@ func TestRegisterCreatorMultipleImplementationsKeyed(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, "firas") + RegisterKeyedCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, "firas") - RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, "firas") + RegisterKeyedCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, "firas") RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) @@ -162,13 +162,13 @@ func TestRegisterCreatorTransientState(t *testing.T) { func TestRegisterCreatorNilKeyOnRegistering(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}, "", nil) + RegisterKeyedCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}, "", nil) }) } func TestRegisterCreatorNilKeyOnGetting(t *testing.T) { clearAll() - RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}, "firas") + RegisterKeyedCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}, "firas") assert.Panics(t, func() { Get[interfaces.SomeCounter](context.Background(), nil) }) diff --git a/default_container_keyed_registerers.go b/default_container_keyed_registerers.go new file mode 100644 index 0000000..df2caff --- /dev/null +++ b/default_container_keyed_registerers.go @@ -0,0 +1,40 @@ +package ore + +import "context" + +// RegisterKeyedCreator Registers a lazily initialized value using a `Creator[T]` interface +func RegisterKeyedCreator[T any](lifetime Lifetime, creator Creator[T], key ...KeyStringer) { + registerCreatorToContainer[T](DefaultContainer, lifetime, creator, key...) +} + +// RegisterKeyedSingleton Registers an eagerly instantiated singleton value +// To register an eagerly instantiated scoped value use [ProvideScopedValue] +func RegisterKeyedSingleton[T comparable](impl T, key ...KeyStringer) { + registerSingletonToContainer[T](DefaultContainer, impl, key...) +} + +// RegisterKeyedFunc Registers a lazily initialized value using an `Initializer[T]` function signature +func RegisterKeyedFunc[T any](lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { + registerFuncToContainer(DefaultContainer, lifetime, initializer, key...) +} + +// RegisterKeyedAlias Registers an interface type to a concrete implementation. +// Allowing you to register the concrete implementation to the default container and later get the interface from it. +func RegisterKeyedAlias[TInterface, TImpl any]() { + registerAliasToContainer[TInterface, TImpl](DefaultContainer) +} + +// RegisterKeyedPlaceholder registers a future value with Scoped lifetime. +// This value will be injected in runtime using the [ProvideScopedValue] function. +// Resolving objects which depend on this value will panic if the value has not been provided. +// Placeholder with the same type and key can be registered only once. +func RegisterKeyedPlaceholder[T comparable](key ...KeyStringer) { + registerPlaceholderToContainer[T](DefaultContainer, key...) +} + +// ProvideKeyedScopedValue injects a concrete value into the given context. +// This value will be available only to the default container. And the container can only resolve this value if +// it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholder] function for more info. +func ProvideKeyedScopedValue[T comparable](ctx context.Context, value T, key ...KeyStringer) context.Context { + return provideScopedValueToContainer(DefaultContainer, ctx, value, key...) +} diff --git a/default_container_registerers.go b/default_container_unkeyed_registerers.go similarity index 81% rename from default_container_registerers.go rename to default_container_unkeyed_registerers.go index d101139..e2a0a96 100644 --- a/default_container_registerers.go +++ b/default_container_unkeyed_registerers.go @@ -3,19 +3,19 @@ package ore import "context" // RegisterCreator Registers a lazily initialized value using a `Creator[T]` interface -func RegisterCreator[T any](lifetime Lifetime, creator Creator[T], key ...KeyStringer) { - registerCreatorToContainer[T](DefaultContainer, lifetime, creator, key...) +func RegisterCreator[T any](lifetime Lifetime, creator Creator[T]) { + registerCreatorToContainer[T](DefaultContainer, lifetime, creator) } // RegisterSingleton Registers an eagerly instantiated singleton value // To register an eagerly instantiated scoped value use [ProvideScopedValue] -func RegisterSingleton[T comparable](impl T, key ...KeyStringer) { - registerSingletonToContainer[T](DefaultContainer, impl, key...) +func RegisterSingleton[T comparable](impl T) { + registerSingletonToContainer[T](DefaultContainer, impl) } // RegisterFunc Registers a lazily initialized value using an `Initializer[T]` function signature -func RegisterFunc[T any](lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { - registerFuncToContainer(DefaultContainer, lifetime, initializer, key...) +func RegisterFunc[T any](lifetime Lifetime, initializer Initializer[T]) { + registerFuncToContainer(DefaultContainer, lifetime, initializer) } // RegisterAlias Registers an interface type to a concrete implementation. @@ -28,13 +28,13 @@ func RegisterAlias[TInterface, TImpl any]() { // This value will be injected in runtime using the [ProvideScopedValue] function. // Resolving objects which depend on this value will panic if the value has not been provided. // Placeholder with the same type and key can be registered only once. -func RegisterPlaceholder[T comparable](key ...KeyStringer) { - registerPlaceholderToContainer[T](DefaultContainer, key...) +func RegisterPlaceholder[T comparable]() { + registerPlaceholderToContainer[T](DefaultContainer) } // ProvideScopedValue injects a concrete value into the given context. // This value will be available only to the default container. And the container can only resolve this value if // it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholder] function for more info. -func ProvideScopedValue[T comparable](ctx context.Context, value T, key ...KeyStringer) context.Context { - return provideScopedValueToContainer(DefaultContainer, ctx, value, key...) +func ProvideScopedValue[T comparable](ctx context.Context, value T) context.Context { + return provideScopedValueToContainer(DefaultContainer, ctx, value) } diff --git a/eager_singleton_test.go b/eager_singleton_test.go index 089154a..ae0db61 100644 --- a/eager_singleton_test.go +++ b/eager_singleton_test.go @@ -48,8 +48,8 @@ func TestRegisterEagerSingletonMultipleImplementations(t *testing.T) { func TestRegisterEagerSingletonMultipleImplementationsKeyed(t *testing.T) { clearAll() - RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") - RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") + RegisterKeyedSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") + RegisterKeyedSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) @@ -85,13 +85,13 @@ func TestRegisterEagerSingletonSingletonState(t *testing.T) { func TestRegisterEagerSingletonNilKeyOnRegistering(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, nil, "") + RegisterKeyedSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, nil, "") }) } func TestRegisterEagerSingletonNilKeyOnGetting(t *testing.T) { clearAll() - RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") + RegisterKeyedSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") assert.Panics(t, func() { Get[interfaces.SomeCounter](context.Background(), nil, "") }) diff --git a/get_list_test.go b/get_list_test.go index e044425..82d7ebf 100644 --- a/get_list_test.go +++ b/get_list_test.go @@ -35,10 +35,10 @@ func TestGetListKeyed(t *testing.T) { key := "somekeyhere" - RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, key) - RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, key) - RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, key) - RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, "Firas") + RegisterKeyedCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, key) + RegisterKeyedCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, key) + RegisterKeyedCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, key) + RegisterKeyedCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, "Firas") counters, _ := GetList[interfaces.SomeCounter](context.Background(), key) if got := len(counters); got != 3 { diff --git a/get_test.go b/get_test.go index 369a32f..9e284d9 100644 --- a/get_test.go +++ b/get_test.go @@ -63,7 +63,7 @@ func TestGetKeyed(t *testing.T) { key := fmt.Sprintf("keynum: %v", i) - RegisterCreator[interfaces.SomeCounter](registrationType, &m.SimpleCounter{}, key) + RegisterKeyedCreator[interfaces.SomeCounter](registrationType, &m.SimpleCounter{}, key) c, _ := Get[interfaces.SomeCounter](context.Background(), key) @@ -97,7 +97,7 @@ func TestGetResolvedSingletons(t *testing.T) { RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService4, context.Context) { return &m.DisposableService4{Name: "X1"}, ctx }) - RegisterFunc(Singleton, func(ctx context.Context) (*m.DisposableService4, context.Context) { + RegisterKeyedFunc(Singleton, func(ctx context.Context) (*m.DisposableService4, context.Context) { return &m.DisposableService4{Name: "X2"}, ctx }, "somekey") @@ -199,7 +199,7 @@ func TestGetResolvedScopedInstances(t *testing.T) { RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService1, context.Context) { return &m.DisposableService1{Name: "S2"}, ctx }) - RegisterFunc(Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { + RegisterKeyedFunc(Scoped, func(ctx context.Context) (*m.DisposableService2, context.Context) { return &m.DisposableService2{Name: "T1"}, ctx }, "module1") diff --git a/initializer_test.go b/initializer_test.go index 06603c3..1b4d505 100644 --- a/initializer_test.go +++ b/initializer_test.go @@ -77,11 +77,11 @@ func TestRegisterFuncMultipleImplementationsKeyed(t *testing.T) { for _, registrationType := range types { clearAll() - RegisterFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterKeyedFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }, "firas") - RegisterFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterKeyedFunc[interfaces.SomeCounter](registrationType, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }, "firas") @@ -182,7 +182,7 @@ func TestRegisterFuncTransientState(t *testing.T) { func TestRegisterFuncNilKeyOnRegistering(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterKeyedFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }, "", nil) }) @@ -190,7 +190,7 @@ func TestRegisterFuncNilKeyOnRegistering(t *testing.T) { func TestRegisterFuncNilKeyOnGetting(t *testing.T) { clearAll() - RegisterFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { + RegisterKeyedFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx }, "firas") diff --git a/registrars_placeholder_test.go b/registrars_placeholder_test.go index ea28c5f..478a6aa 100644 --- a/registrars_placeholder_test.go +++ b/registrars_placeholder_test.go @@ -71,34 +71,34 @@ func TestPlaceHolder_OverrideRealResolver(t *testing.T) { clearAll() //register a real resolver - RegisterSingleton(&m.Trader{Name: "Mary"}, "module1") + RegisterKeyedSingleton(&m.Trader{Name: "Mary"}, "module1") //register a placeHolder to override the real resolver should failed assert2.PanicsWithError(t, assert2.ErrorContains("has already been registered"), func() { - RegisterPlaceholder[*m.Trader]("module1") + RegisterKeyedPlaceholder[*m.Trader]("module1") }) //register 2 time a placeHolder should failed - RegisterPlaceholder[*m.Trader]("module2") + RegisterKeyedPlaceholder[*m.Trader]("module2") assert2.PanicsWithError(t, assert2.ErrorContains("has already been registered"), func() { - RegisterPlaceholder[*m.Trader]("module2") + RegisterKeyedPlaceholder[*m.Trader]("module2") }) } func TestPlaceHolder_OverridePlaceHolder(t *testing.T) { clearAll() //register a placeHolder - RegisterPlaceholder[*m.Trader]("module2") + RegisterKeyedPlaceholder[*m.Trader]("module2") //Provide the value to the placeHolder - ctx := ProvideScopedValue[*m.Trader](context.Background(), &m.Trader{Name: "John"}, "module2") + ctx := ProvideKeyedScopedValue[*m.Trader](context.Background(), &m.Trader{Name: "John"}, "module2") //get the placeHolder value would success trader, ctx := Get[*m.Trader](ctx, "module2") assert.Equal(t, "John", trader.Name) //replace the placeHolder value "John" with a new value "David" - ctx = ProvideScopedValue[*m.Trader](ctx, &m.Trader{Name: "David"}, "module2") + ctx = ProvideKeyedScopedValue[*m.Trader](ctx, &m.Trader{Name: "David"}, "module2") trader, ctx = Get[*m.Trader](ctx, "module2") assert.Equal(t, "David", trader.Name) @@ -107,7 +107,7 @@ func TestPlaceHolder_OverridePlaceHolder(t *testing.T) { assert.Equal(t, "David", traders[0].Name) //Register a real resolver should override the placeHolder resolver - RegisterFunc(Singleton, func(ctx context.Context) (*m.Trader, context.Context) { + RegisterKeyedFunc(Singleton, func(ctx context.Context) (*m.Trader, context.Context) { return &m.Trader{Name: "Mary"}, ctx }, "module2") @@ -121,7 +121,7 @@ func TestPlaceHolder_OverridePlaceHolder(t *testing.T) { assert.True(t, tradersListContainsName(traders, "Mary")) //replace the placeHolder value ("David") with a new value ("Nathan") - ctx = ProvideScopedValue[*m.Trader](ctx, &m.Trader{Name: "Nathan"}, "module2") + ctx = ProvideKeyedScopedValue[*m.Trader](ctx, &m.Trader{Name: "Nathan"}, "module2") //the placeHolder value cannot override the real resolver value trader, ctx = Get[*m.Trader](ctx, "module2") From 1606bc8698281f2c334d668f544aaaee55464a0f Mon Sep 17 00:00:00 2001 From: Firas Darwish Date: Fri, 15 Nov 2024 14:28:45 +0300 Subject: [PATCH 04/12] make key a single value instead of variadic arg --- container_keyed_registerers.go | 20 ++++----- container_unkeyed_registerers.go | 10 ++--- default_container_keyed_registerers.go | 20 ++++----- default_container_unkeyed_registerers.go | 11 ++--- internal_registerers.go | 20 ++++----- key.go | 23 ++-------- key_test.go | 53 ------------------------ ore.go | 17 +++----- ore_test.go | 10 ++--- 9 files changed, 56 insertions(+), 128 deletions(-) diff --git a/container_keyed_registerers.go b/container_keyed_registerers.go index 9e7f3cc..411df86 100644 --- a/container_keyed_registerers.go +++ b/container_keyed_registerers.go @@ -5,19 +5,19 @@ import ( ) // RegisterKeyedCreatorToContainer Registers a lazily initialized value to the given container using a `Creator[T]` interface -func RegisterKeyedCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T], key ...KeyStringer) { - registerCreatorToContainer(con, lifetime, creator, key...) +func RegisterKeyedCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T], key KeyStringer) { + registerCreatorToContainer(con, lifetime, creator, key) } // RegisterKeyedSingletonToContainer Registers an eagerly instantiated singleton value to the given container. // To register an eagerly instantiated scoped value use [ProvideScopedValueToContainer] -func RegisterKeyedSingletonToContainer[T comparable](con *Container, impl T, key ...KeyStringer) { - registerSingletonToContainer(con, impl, key...) +func RegisterKeyedSingletonToContainer[T comparable](con *Container, impl T, key KeyStringer) { + registerSingletonToContainer(con, impl, key) } // RegisterKeyedFuncToContainer Registers a lazily initialized value to the given container using an `Initializer[T]` function signature -func RegisterKeyedFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { - registerFuncToContainer(con, lifetime, initializer, key...) +func RegisterKeyedFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T], key KeyStringer) { + registerFuncToContainer(con, lifetime, initializer, key) } // TODO move to sep file @@ -31,13 +31,13 @@ func RegisterAliasToContainer[TInterface, TImpl any](con *Container) { // This value will be injected in runtime using the [ProvideScopedValue] function. // Resolving objects which depend on this value will panic if the value has not been provided. // Placeholder with the same type and key can be registered only once. -func RegisterKeyedPlaceholderToContainer[T comparable](con *Container, key ...KeyStringer) { - registerPlaceholderToContainer[T](con, key...) +func RegisterKeyedPlaceholderToContainer[T comparable](con *Container, key KeyStringer) { + registerPlaceholderToContainer[T](con, key) } // ProvideKeyedScopedValueToContainer injects a concrete value into the given context. // This value will be available only to the given container. And the container can only resolve this value if // it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholderToContainer] function for more info. -func ProvideKeyedScopedValueToContainer[T comparable](con *Container, ctx context.Context, value T, key ...KeyStringer) context.Context { - return provideScopedValueToContainer(con, ctx, value, key...) +func ProvideKeyedScopedValueToContainer[T comparable](con *Container, ctx context.Context, value T, key KeyStringer) context.Context { + return provideScopedValueToContainer(con, ctx, value, key) } diff --git a/container_unkeyed_registerers.go b/container_unkeyed_registerers.go index 7cf3628..add8a83 100644 --- a/container_unkeyed_registerers.go +++ b/container_unkeyed_registerers.go @@ -6,18 +6,18 @@ import ( // RegisterCreatorToContainer Registers a lazily initialized value to the given container using a `Creator[T]` interface func RegisterCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T]) { - registerCreatorToContainer(con, lifetime, creator) + registerCreatorToContainer(con, lifetime, creator, nil) } // RegisterSingletonToContainer Registers an eagerly instantiated singleton value to the given container. // To register an eagerly instantiated scoped value use [ProvideScopedValueToContainer] func RegisterSingletonToContainer[T comparable](con *Container, impl T) { - registerSingletonToContainer(con, impl) + registerSingletonToContainer(con, impl, nil) } // RegisterFuncToContainer Registers a lazily initialized value to the given container using an `Initializer[T]` function signature func RegisterFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T]) { - registerFuncToContainer(con, lifetime, initializer) + registerFuncToContainer(con, lifetime, initializer, nil) } // RegisterPlaceholderToContainer registers a future value with Scoped lifetime to the given container. @@ -25,12 +25,12 @@ func RegisterFuncToContainer[T any](con *Container, lifetime Lifetime, initializ // Resolving objects which depend on this value will panic if the value has not been provided. // Placeholder with the same type and key can be registered only once. func RegisterPlaceholderToContainer[T comparable](con *Container) { - registerPlaceholderToContainer[T](con) + registerPlaceholderToContainer[T](con, nil) } // ProvideScopedValueToContainer injects a concrete value into the given context. // This value will be available only to the given container. And the container can only resolve this value if // it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholderToContainer] function for more info. func ProvideScopedValueToContainer[T comparable](con *Container, ctx context.Context, value T) context.Context { - return provideScopedValueToContainer(con, ctx, value) + return provideScopedValueToContainer(con, ctx, value, nil) } diff --git a/default_container_keyed_registerers.go b/default_container_keyed_registerers.go index df2caff..2042db0 100644 --- a/default_container_keyed_registerers.go +++ b/default_container_keyed_registerers.go @@ -3,19 +3,19 @@ package ore import "context" // RegisterKeyedCreator Registers a lazily initialized value using a `Creator[T]` interface -func RegisterKeyedCreator[T any](lifetime Lifetime, creator Creator[T], key ...KeyStringer) { - registerCreatorToContainer[T](DefaultContainer, lifetime, creator, key...) +func RegisterKeyedCreator[T any](lifetime Lifetime, creator Creator[T], key KeyStringer) { + registerCreatorToContainer[T](DefaultContainer, lifetime, creator, key) } // RegisterKeyedSingleton Registers an eagerly instantiated singleton value // To register an eagerly instantiated scoped value use [ProvideScopedValue] -func RegisterKeyedSingleton[T comparable](impl T, key ...KeyStringer) { - registerSingletonToContainer[T](DefaultContainer, impl, key...) +func RegisterKeyedSingleton[T comparable](impl T, key KeyStringer) { + registerSingletonToContainer[T](DefaultContainer, impl, key) } // RegisterKeyedFunc Registers a lazily initialized value using an `Initializer[T]` function signature -func RegisterKeyedFunc[T any](lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { - registerFuncToContainer(DefaultContainer, lifetime, initializer, key...) +func RegisterKeyedFunc[T any](lifetime Lifetime, initializer Initializer[T], key KeyStringer) { + registerFuncToContainer(DefaultContainer, lifetime, initializer, key) } // RegisterKeyedAlias Registers an interface type to a concrete implementation. @@ -28,13 +28,13 @@ func RegisterKeyedAlias[TInterface, TImpl any]() { // This value will be injected in runtime using the [ProvideScopedValue] function. // Resolving objects which depend on this value will panic if the value has not been provided. // Placeholder with the same type and key can be registered only once. -func RegisterKeyedPlaceholder[T comparable](key ...KeyStringer) { - registerPlaceholderToContainer[T](DefaultContainer, key...) +func RegisterKeyedPlaceholder[T comparable](key KeyStringer) { + registerPlaceholderToContainer[T](DefaultContainer, key) } // ProvideKeyedScopedValue injects a concrete value into the given context. // This value will be available only to the default container. And the container can only resolve this value if // it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholder] function for more info. -func ProvideKeyedScopedValue[T comparable](ctx context.Context, value T, key ...KeyStringer) context.Context { - return provideScopedValueToContainer(DefaultContainer, ctx, value, key...) +func ProvideKeyedScopedValue[T comparable](ctx context.Context, value T, key KeyStringer) context.Context { + return provideScopedValueToContainer(DefaultContainer, ctx, value, key) } diff --git a/default_container_unkeyed_registerers.go b/default_container_unkeyed_registerers.go index e2a0a96..3de1e5b 100644 --- a/default_container_unkeyed_registerers.go +++ b/default_container_unkeyed_registerers.go @@ -4,20 +4,21 @@ import "context" // RegisterCreator Registers a lazily initialized value using a `Creator[T]` interface func RegisterCreator[T any](lifetime Lifetime, creator Creator[T]) { - registerCreatorToContainer[T](DefaultContainer, lifetime, creator) + registerCreatorToContainer[T](DefaultContainer, lifetime, creator, nil) } // RegisterSingleton Registers an eagerly instantiated singleton value // To register an eagerly instantiated scoped value use [ProvideScopedValue] func RegisterSingleton[T comparable](impl T) { - registerSingletonToContainer[T](DefaultContainer, impl) + registerSingletonToContainer[T](DefaultContainer, impl, nil) } // RegisterFunc Registers a lazily initialized value using an `Initializer[T]` function signature func RegisterFunc[T any](lifetime Lifetime, initializer Initializer[T]) { - registerFuncToContainer(DefaultContainer, lifetime, initializer) + registerFuncToContainer(DefaultContainer, lifetime, initializer, nil) } +// TODO move to separate file // RegisterAlias Registers an interface type to a concrete implementation. // Allowing you to register the concrete implementation to the default container and later get the interface from it. func RegisterAlias[TInterface, TImpl any]() { @@ -29,12 +30,12 @@ func RegisterAlias[TInterface, TImpl any]() { // Resolving objects which depend on this value will panic if the value has not been provided. // Placeholder with the same type and key can be registered only once. func RegisterPlaceholder[T comparable]() { - registerPlaceholderToContainer[T](DefaultContainer) + registerPlaceholderToContainer[T](DefaultContainer, nil) } // ProvideScopedValue injects a concrete value into the given context. // This value will be available only to the default container. And the container can only resolve this value if // it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholder] function for more info. func ProvideScopedValue[T comparable](ctx context.Context, value T) context.Context { - return provideScopedValueToContainer(DefaultContainer, ctx, value) + return provideScopedValueToContainer(DefaultContainer, ctx, value, nil) } diff --git a/internal_registerers.go b/internal_registerers.go index 8296ca7..dc74a76 100644 --- a/internal_registerers.go +++ b/internal_registerers.go @@ -7,7 +7,7 @@ import ( "time" ) -func registerCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T], key ...KeyStringer) { +func registerCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T], key KeyStringer) { if creator == nil { panic(nilVal[T]()) } @@ -18,10 +18,10 @@ func registerCreatorToContainer[T any](con *Container, lifetime Lifetime, creato }, creatorInstance: creator, } - addResolver[T](con, e, key...) + addResolver[T](con, e, key) } -func registerSingletonToContainer[T comparable](con *Container, impl T, key ...KeyStringer) { +func registerSingletonToContainer[T comparable](con *Container, impl T, key KeyStringer) { if isNil[T](impl) { panic(nilVal[T]()) } @@ -36,10 +36,10 @@ func registerSingletonToContainer[T comparable](con *Container, impl T, key ...K invocationTime: time.Now(), }, } - addResolver[T](con, e, key...) + addResolver[T](con, e, key) } -func registerFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T], key ...KeyStringer) { +func registerFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T], key KeyStringer) { if initializer == nil { panic(nilVal[T]()) } @@ -50,7 +50,7 @@ func registerFuncToContainer[T any](con *Container, lifetime Lifetime, initializ }, anonymousInitializer: &initializer, } - addResolver[T](con, e, key...) + addResolver[T](con, e, key) } func registerAliasToContainer[TInterface, TImpl any](con *Container) { @@ -64,16 +64,16 @@ func registerAliasToContainer[TInterface, TImpl any](con *Container) { addAliases[TInterface, TImpl](con) } -func registerPlaceholderToContainer[T comparable](con *Container, key ...KeyStringer) { +func registerPlaceholderToContainer[T comparable](con *Container, key KeyStringer) { e := serviceResolverImpl[T]{ resolverMetadata: resolverMetadata{ lifetime: Scoped, }, } - addResolver[T](con, e, key...) + addResolver[T](con, e, key) } -func provideScopedValueToContainer[T comparable](con *Container, ctx context.Context, value T, key ...KeyStringer) context.Context { +func provideScopedValueToContainer[T comparable](con *Container, ctx context.Context, value T, key KeyStringer) context.Context { concreteValue := &concrete{ value: value, lifetime: Scoped, @@ -82,7 +82,7 @@ func provideScopedValueToContainer[T comparable](con *Container, ctx context.Con } id := contextKey{ containerID: con.containerID, - typeID: typeIdentifier[T](key...), + typeID: typeIdentifier[T](key), resolverID: placeHolderResolverID, } return addScopedConcreteToContext(ctx, id, concreteValue) diff --git a/key.go b/key.go index b460f3d..64a7c2f 100644 --- a/key.go +++ b/key.go @@ -3,32 +3,17 @@ package ore import ( "reflect" "strconv" - "strings" ) type KeyStringer any -func oreKey(key ...KeyStringer) string { +func oreKey(key KeyStringer) string { if key == nil { - return "" + return "n" } - l := len(key) - - if l == 1 { - keyT, kV := stringifyOreKey(key[0]) - return keyT + kV - } - - var sb strings.Builder - - for _, s := range key { - keyT, keyV := stringifyOreKey(s) - sb.WriteString(keyT) - sb.WriteString(keyV) - } - - return sb.String() + keyT, kV := stringifyOreKey(key) + return keyT + kV } func stringifyOreKey(key KeyStringer) (string, string) { diff --git a/key_test.go b/key_test.go index 23de674..41cd0e1 100644 --- a/key_test.go +++ b/key_test.go @@ -14,14 +14,6 @@ func TestOreKeyNil(t *testing.T) { } } -func TestOreKeyEmpty(t *testing.T) { - k := oreKey() - - if got := k; got != "" { - t.Errorf("got `%v`, expected `%v`", got, "s") - } -} - func TestOreKey1String(t *testing.T) { k := oreKey("ore") expect := "sore" @@ -31,15 +23,6 @@ func TestOreKey1String(t *testing.T) { } } -func TestOreKey2String(t *testing.T) { - k := oreKey("ore", "package") - expect := "sorespackage" - - if got := k; got != expect { - t.Errorf("got `%v`, expected `%v`", got, expect) - } -} - func TestOreKey1Int(t *testing.T) { k := oreKey(10) expect := "i10" @@ -49,33 +32,6 @@ func TestOreKey1Int(t *testing.T) { } } -func TestOreKey2Int(t *testing.T) { - k := oreKey(10, 30) - expect := "i10i30" - - if got := k; got != expect { - t.Errorf("got `%v`, expected `%v`", got, expect) - } -} - -func TestOreKeyStringInt(t *testing.T) { - k := oreKey("ore", 97) - expect := "sorei97" - - if got := k; got != expect { - t.Errorf("got `%v`, expected `%v`", got, expect) - } -} - -func TestOreKey2StringInt(t *testing.T) { - k := oreKey("ore", 97, "di", 5) - expect := "sorei97sdii5" - - if got := k; got != expect { - t.Errorf("got `%v`, expected `%v`", got, expect) - } -} - func TestOreKeyUint(t *testing.T) { var n uint n = 5 @@ -117,12 +73,3 @@ func TestOreKeyStruct(t *testing.T) { oreKey(n) }) } - -func TestOreKeyVarious(t *testing.T) { - k := oreKey("firas", 16, "ore", 3.14, 1/6, -9, -1494546.452) - expect := "sfirasi16soref640x1.91eb851eb851fp+01i0i-9f64-0x1.6ce1273b645a2p+20" - - if got := k; got != expect { - t.Errorf("got `%v`, expected `%v`", got, expect) - } -} diff --git a/ore.go b/ore.go index 3fd1227..be51ce6 100644 --- a/ore.go +++ b/ore.go @@ -30,27 +30,22 @@ func init() { } // Generates a unique identifier for a service resolver based on type and key(s) -func getTypeID(pointerTypeName pointerTypeName, key ...KeyStringer) typeID { - for _, stringer := range key { - if stringer == nil { - panic(nilKey) - } - } - return typeID{pointerTypeName, oreKey(key...)} +func getTypeID(pointerTypeName pointerTypeName, key KeyStringer) typeID { + return typeID{pointerTypeName, oreKey(key)} } // Generates a unique identifier for a service resolver based on type and key(s) -func typeIdentifier[T any](key ...KeyStringer) typeID { - return getTypeID(getPointerTypeName[T](), key...) +func typeIdentifier[T any](key KeyStringer) typeID { + return getTypeID(getPointerTypeName[T](), key) } // Appends a service resolver to the container with type and key -func addResolver[T any](this *Container, resolver serviceResolverImpl[T], key ...KeyStringer) { +func addResolver[T any](this *Container, resolver serviceResolverImpl[T], key KeyStringer) { if this.isSealed { panic(alreadyBuiltCannotAdd) } - typeID := typeIdentifier[T](key...) + typeID := typeIdentifier[T](key) this.lock.Lock() defer this.lock.Unlock() diff --git a/ore_test.go b/ore_test.go index 8c98f3d..41acac9 100644 --- a/ore_test.go +++ b/ore_test.go @@ -76,13 +76,13 @@ type A1 struct{} type A2 struct{} func TestTypeIdentifier(t *testing.T) { - id1 := typeIdentifier[*A1]() - id11 := typeIdentifier[*A1]() - id2 := typeIdentifier[*A2]() + id1 := typeIdentifier[*A1](nil) + id11 := typeIdentifier[*A1](nil) + id2 := typeIdentifier[*A2](nil) assert.NotEqual(t, id1, id2) assert.Equal(t, id1, id11) - id3 := typeIdentifier[*A1]("a", "b") - id4 := typeIdentifier[*A1]("a", "b") + id3 := typeIdentifier[*A1]("a") + id4 := typeIdentifier[*A1]("a") assert.Equal(t, id3, id4) } From ca3ee4f9c80f519acd5f99f088d55a6b5dcbf3a5 Mon Sep 17 00:00:00 2001 From: Firas Darwish Date: Fri, 15 Nov 2024 14:33:12 +0300 Subject: [PATCH 05/12] separete defaultContainer getters --- getters.go => container_getters.go | 51 ++---------------------------- default_container_getters.go | 15 +++++++++ internal_getters.go | 41 ++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 49 deletions(-) rename getters.go => container_getters.go (79%) create mode 100644 default_container_getters.go create mode 100644 internal_getters.go diff --git a/getters.go b/container_getters.go similarity index 79% rename from getters.go rename to container_getters.go index f683385..8ab4b43 100644 --- a/getters.go +++ b/container_getters.go @@ -2,30 +2,8 @@ package ore import ( "context" - "sort" ) -func (this *Container) getLastRegisteredResolver(typeID typeID) serviceResolver { - // try to get service resolver from container - this.lock.RLock() - resolvers, resolverExists := this.resolvers[typeID] - this.lock.RUnlock() - - if !resolverExists { - return nil - } - - count := len(resolvers) - - if count == 0 { - return nil - } - - // index of the last implementation - lastIndex := count - 1 - return resolvers[lastIndex] -} - // GetFromContainer Retrieves an instance from the given container based on type and key (panics if no valid implementations) func GetFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) (T, context.Context) { pointerTypeName := getPointerTypeName[T]() @@ -60,11 +38,6 @@ func GetFromContainer[T any](con *Container, ctx context.Context, key ...KeyStri return concrete.value.(T), ctx } -// Get Retrieves an instance based on type and key (panics if no valid implementations) -func Get[T any](ctx context.Context, key ...KeyStringer) (T, context.Context) { - return GetFromContainer[T](DefaultContainer, ctx, key...) -} - // GetListFromContainer Retrieves a list of instances from the given container based on type and key func GetListFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) ([]T, context.Context) { inputPointerTypeName := getPointerTypeName[T]() @@ -111,11 +84,6 @@ func GetListFromContainer[T any](con *Container, ctx context.Context, key ...Key return servicesArray, ctx } -// GetList Retrieves a list of instances based on type and key -func GetList[T any](ctx context.Context, key ...KeyStringer) ([]T, context.Context) { - return GetListFromContainer[T](DefaultContainer, ctx, key...) -} - // GetResolvedSingletonsFromContainer retrieves a list of Singleton instances that implement the [TInterface] from the given container. // See [GetResolvedSingletons] for more information. func GetResolvedSingletonsFromContainer[TInterface any](con *Container) []TInterface { @@ -139,6 +107,7 @@ func GetResolvedSingletonsFromContainer[TInterface any](con *Container) []TInter return sortAndSelect[TInterface](list) } +// TODO separate to a file // GetResolvedSingletons retrieves a list of Singleton instances that implement the [TInterface]. // The returned instances are sorted by creation time (a.k.a the invocation order), the first one being the "most recently" created one. // If an instance "A" depends on certain instances "B" and "C" then this function guarantee to return "B" and "C" before "A" in the list. @@ -155,6 +124,7 @@ func GetResolvedSingletons[TInterface any]() []TInterface { return GetResolvedSingletonsFromContainer[TInterface](DefaultContainer) } +// TODO separate to a file // GetResolvedScopedInstances retrieves a list of Scoped instances that implement the [TInterface]. // The returned instances are sorted by creation time (a.k.a the invocation order), the first one being the most recently created one. // If an instance "A" depends on certain instances "B" and "C" then this function guarantee to return "B" and "C" before "A" in the list. @@ -185,20 +155,3 @@ func GetResolvedScopedInstances[TInterface any](ctx context.Context) []TInterfac return sortAndSelect[TInterface](list) } - -// sortAndSelect sorts concretes by invocation order and return its value. -func sortAndSelect[TInterface any](list []*concrete) []TInterface { - //sorting - sort.Slice(list, func(i, j int) bool { - return list[i].invocationTime.After(list[j].invocationTime) || - (list[i].invocationTime == list[j].invocationTime && - list[i].invocationLevel > list[j].invocationLevel) - }) - - //selecting - result := make([]TInterface, len(list)) - for i := 0; i < len(list); i++ { - result[i] = list[i].value.(TInterface) - } - return result -} diff --git a/default_container_getters.go b/default_container_getters.go new file mode 100644 index 0000000..bc6fad5 --- /dev/null +++ b/default_container_getters.go @@ -0,0 +1,15 @@ +package ore + +import ( + "context" +) + +// Get Retrieves an instance based on type and key (panics if no valid implementations) +func Get[T any](ctx context.Context, key ...KeyStringer) (T, context.Context) { + return GetFromContainer[T](DefaultContainer, ctx, key...) +} + +// GetList Retrieves a list of instances based on type and key +func GetList[T any](ctx context.Context, key ...KeyStringer) ([]T, context.Context) { + return GetListFromContainer[T](DefaultContainer, ctx, key...) +} diff --git a/internal_getters.go b/internal_getters.go new file mode 100644 index 0000000..8a2bce9 --- /dev/null +++ b/internal_getters.go @@ -0,0 +1,41 @@ +package ore + +import "sort" + +func (this *Container) getLastRegisteredResolver(typeID typeID) serviceResolver { + // try to get service resolver from container + this.lock.RLock() + resolvers, resolverExists := this.resolvers[typeID] + this.lock.RUnlock() + + if !resolverExists { + return nil + } + + count := len(resolvers) + + if count == 0 { + return nil + } + + // index of the last implementation + lastIndex := count - 1 + return resolvers[lastIndex] +} + +// sortAndSelect sorts concretes by invocation order and return its value. +func sortAndSelect[TInterface any](list []*concrete) []TInterface { + //sorting + sort.Slice(list, func(i, j int) bool { + return list[i].invocationTime.After(list[j].invocationTime) || + (list[i].invocationTime == list[j].invocationTime && + list[i].invocationLevel > list[j].invocationLevel) + }) + + //selecting + result := make([]TInterface, len(list)) + for i := 0; i < len(list); i++ { + result[i] = list[i].value.(TInterface) + } + return result +} From 408a56fc32372a6cf45caa84f4b8de0fc3bab201 Mon Sep 17 00:00:00 2001 From: Firas Darwish Date: Fri, 15 Nov 2024 14:37:30 +0300 Subject: [PATCH 06/12] push getters info shared internal funcs --- container_getters.go | 95 ++------------------------------ default_container_getters.go | 4 +- internal_getters.go | 104 ++++++++++++++++++++++++++++++++++- 3 files changed, 109 insertions(+), 94 deletions(-) diff --git a/container_getters.go b/container_getters.go index 8ab4b43..70f64e5 100644 --- a/container_getters.go +++ b/container_getters.go @@ -6,105 +6,18 @@ import ( // GetFromContainer Retrieves an instance from the given container based on type and key (panics if no valid implementations) func GetFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) (T, context.Context) { - pointerTypeName := getPointerTypeName[T]() - typeID := getTypeID(pointerTypeName, key...) - lastRegisteredResolver := con.getLastRegisteredResolver(typeID) - if lastRegisteredResolver == nil { //not found, T is an alias - - con.lock.RLock() - implementations, implExists := con.aliases[pointerTypeName] - con.lock.RUnlock() - - if !implExists { - panic(noValidImplementation[T]()) - } - count := len(implementations) - if count == 0 { - panic(noValidImplementation[T]()) - } - for i := count - 1; i >= 0; i-- { - impl := implementations[i] - typeID = getTypeID(impl, key...) - lastRegisteredResolver = con.getLastRegisteredResolver(typeID) - if lastRegisteredResolver != nil { - break - } - } - } - if lastRegisteredResolver == nil { - panic(noValidImplementation[T]()) - } - concrete, ctx := lastRegisteredResolver.resolveService(con, ctx) - return concrete.value.(T), ctx + return getFromContainer[T](con, ctx, key...) } // GetListFromContainer Retrieves a list of instances from the given container based on type and key func GetListFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) ([]T, context.Context) { - inputPointerTypeName := getPointerTypeName[T]() - - con.lock.RLock() - pointerTypeNames, implExists := con.aliases[inputPointerTypeName] - con.lock.RUnlock() - - if implExists { - pointerTypeNames = append(pointerTypeNames, inputPointerTypeName) - } else { - pointerTypeNames = []pointerTypeName{inputPointerTypeName} - } - - servicesArray := []T{} - - for i := 0; i < len(pointerTypeNames); i++ { - pointerTypeName := pointerTypeNames[i] - // generate type identifier - typeID := getTypeID(pointerTypeName, key...) - - // try to get service resolver from container - con.lock.RLock() - resolvers, resolverExists := con.resolvers[typeID] - con.lock.RUnlock() - - if !resolverExists { - continue - } - - for index := 0; index < len(resolvers); index++ { - resolver := resolvers[index] - if resolver.isPlaceHolder() && !resolver.isScopedValueResolved(ctx) { - //the resolver is a placeHolder and the placeHolder's value has not been provided - //don't panic, just skip (don't add anything to the list) - continue - } - con, newCtx := resolver.resolveService(con, ctx) - servicesArray = append(servicesArray, con.value.(T)) - ctx = newCtx - } - } - - return servicesArray, ctx + return getListFromContainer[T](con, ctx, key...) } // GetResolvedSingletonsFromContainer retrieves a list of Singleton instances that implement the [TInterface] from the given container. // See [GetResolvedSingletons] for more information. func GetResolvedSingletonsFromContainer[TInterface any](con *Container) []TInterface { - con.lock.RLock() - defer con.lock.RUnlock() - - list := []*concrete{} - - //filtering - for _, resolvers := range con.resolvers { - for _, resolver := range resolvers { - con, isInvokedSingleton := resolver.getInvokedSingleton() - if isInvokedSingleton { - if _, ok := con.value.(TInterface); ok { - list = append(list, con) - } - } - } - } - - return sortAndSelect[TInterface](list) + return getResolvedSingletonsFromContainer[TInterface](con) } // TODO separate to a file @@ -121,7 +34,7 @@ func GetResolvedSingletonsFromContainer[TInterface any](con *Container) []TInter // disposable.Dispose() // } func GetResolvedSingletons[TInterface any]() []TInterface { - return GetResolvedSingletonsFromContainer[TInterface](DefaultContainer) + return getResolvedSingletonsFromContainer[TInterface](DefaultContainer) } // TODO separate to a file diff --git a/default_container_getters.go b/default_container_getters.go index bc6fad5..8d81687 100644 --- a/default_container_getters.go +++ b/default_container_getters.go @@ -6,10 +6,10 @@ import ( // Get Retrieves an instance based on type and key (panics if no valid implementations) func Get[T any](ctx context.Context, key ...KeyStringer) (T, context.Context) { - return GetFromContainer[T](DefaultContainer, ctx, key...) + return getFromContainer[T](DefaultContainer, ctx, key...) } // GetList Retrieves a list of instances based on type and key func GetList[T any](ctx context.Context, key ...KeyStringer) ([]T, context.Context) { - return GetListFromContainer[T](DefaultContainer, ctx, key...) + return getListFromContainer[T](DefaultContainer, ctx, key...) } diff --git a/internal_getters.go b/internal_getters.go index 8a2bce9..98736c7 100644 --- a/internal_getters.go +++ b/internal_getters.go @@ -1,6 +1,9 @@ package ore -import "sort" +import ( + "context" + "sort" +) func (this *Container) getLastRegisteredResolver(typeID typeID) serviceResolver { // try to get service resolver from container @@ -39,3 +42,102 @@ func sortAndSelect[TInterface any](list []*concrete) []TInterface { } return result } + +func getFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) (T, context.Context) { + pointerTypeName := getPointerTypeName[T]() + typeID := getTypeID(pointerTypeName, key...) + lastRegisteredResolver := con.getLastRegisteredResolver(typeID) + if lastRegisteredResolver == nil { //not found, T is an alias + + con.lock.RLock() + implementations, implExists := con.aliases[pointerTypeName] + con.lock.RUnlock() + + if !implExists { + panic(noValidImplementation[T]()) + } + count := len(implementations) + if count == 0 { + panic(noValidImplementation[T]()) + } + for i := count - 1; i >= 0; i-- { + impl := implementations[i] + typeID = getTypeID(impl, key...) + lastRegisteredResolver = con.getLastRegisteredResolver(typeID) + if lastRegisteredResolver != nil { + break + } + } + } + if lastRegisteredResolver == nil { + panic(noValidImplementation[T]()) + } + concrete, ctx := lastRegisteredResolver.resolveService(con, ctx) + return concrete.value.(T), ctx +} + +func getListFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) ([]T, context.Context) { + inputPointerTypeName := getPointerTypeName[T]() + + con.lock.RLock() + pointerTypeNames, implExists := con.aliases[inputPointerTypeName] + con.lock.RUnlock() + + if implExists { + pointerTypeNames = append(pointerTypeNames, inputPointerTypeName) + } else { + pointerTypeNames = []pointerTypeName{inputPointerTypeName} + } + + servicesArray := []T{} + + for i := 0; i < len(pointerTypeNames); i++ { + pointerTypeName := pointerTypeNames[i] + // generate type identifier + typeID := getTypeID(pointerTypeName, key...) + + // try to get service resolver from container + con.lock.RLock() + resolvers, resolverExists := con.resolvers[typeID] + con.lock.RUnlock() + + if !resolverExists { + continue + } + + for index := 0; index < len(resolvers); index++ { + resolver := resolvers[index] + if resolver.isPlaceHolder() && !resolver.isScopedValueResolved(ctx) { + //the resolver is a placeHolder and the placeHolder's value has not been provided + //don't panic, just skip (don't add anything to the list) + continue + } + con, newCtx := resolver.resolveService(con, ctx) + servicesArray = append(servicesArray, con.value.(T)) + ctx = newCtx + } + } + + return servicesArray, ctx +} + +func getResolvedSingletonsFromContainer[TInterface any](con *Container) []TInterface { + con.lock.RLock() + defer con.lock.RUnlock() + + list := []*concrete{} + + //filtering + for _, resolvers := range con.resolvers { + for _, resolver := range resolvers { + con, isInvokedSingleton := resolver.getInvokedSingleton() + if isInvokedSingleton { + if _, ok := con.value.(TInterface); ok { + list = append(list, con) + } + } + } + } + + return sortAndSelect[TInterface](list) +} From 393b84572d03be71f858a8320ac31536d2534c44 Mon Sep 17 00:00:00 2001 From: Firas Darwish Date: Fri, 15 Nov 2024 14:41:31 +0300 Subject: [PATCH 07/12] sep. keyed&unkeyed getters --- container_keyed_getters.go | 15 +++++++++++++++ ...ner_getters.go => container_unkeyed_getters.go | 9 +++++---- default_container_getters.go | 15 --------------- default_container_keyed_getters.go | 15 +++++++++++++++ default_container_unkeyed_getters.go | 15 +++++++++++++++ 5 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 container_keyed_getters.go rename container_getters.go => container_unkeyed_getters.go (93%) delete mode 100644 default_container_getters.go create mode 100644 default_container_keyed_getters.go create mode 100644 default_container_unkeyed_getters.go diff --git a/container_keyed_getters.go b/container_keyed_getters.go new file mode 100644 index 0000000..30c8360 --- /dev/null +++ b/container_keyed_getters.go @@ -0,0 +1,15 @@ +package ore + +import ( + "context" +) + +// GetFromContainer Retrieves an instance from the given container based on type and key (panics if no valid implementations) +func GetKeyedFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) (T, context.Context) { + return getFromContainer[T](con, ctx, key...) +} + +// GetListFromContainer Retrieves a list of instances from the given container based on type and key +func GetKeyedListFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) ([]T, context.Context) { + return getListFromContainer[T](con, ctx, key...) +} diff --git a/container_getters.go b/container_unkeyed_getters.go similarity index 93% rename from container_getters.go rename to container_unkeyed_getters.go index 70f64e5..13bf821 100644 --- a/container_getters.go +++ b/container_unkeyed_getters.go @@ -5,15 +5,16 @@ import ( ) // GetFromContainer Retrieves an instance from the given container based on type and key (panics if no valid implementations) -func GetFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) (T, context.Context) { - return getFromContainer[T](con, ctx, key...) +func GetFromContainer[T any](con *Container, ctx context.Context) (T, context.Context) { + return getFromContainer[T](con, ctx) } // GetListFromContainer Retrieves a list of instances from the given container based on type and key -func GetListFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) ([]T, context.Context) { - return getListFromContainer[T](con, ctx, key...) +func GetListFromContainer[T any](con *Container, ctx context.Context) ([]T, context.Context) { + return getListFromContainer[T](con, ctx) } +// TODO sep. to a file // GetResolvedSingletonsFromContainer retrieves a list of Singleton instances that implement the [TInterface] from the given container. // See [GetResolvedSingletons] for more information. func GetResolvedSingletonsFromContainer[TInterface any](con *Container) []TInterface { diff --git a/default_container_getters.go b/default_container_getters.go deleted file mode 100644 index 8d81687..0000000 --- a/default_container_getters.go +++ /dev/null @@ -1,15 +0,0 @@ -package ore - -import ( - "context" -) - -// Get Retrieves an instance based on type and key (panics if no valid implementations) -func Get[T any](ctx context.Context, key ...KeyStringer) (T, context.Context) { - return getFromContainer[T](DefaultContainer, ctx, key...) -} - -// GetList Retrieves a list of instances based on type and key -func GetList[T any](ctx context.Context, key ...KeyStringer) ([]T, context.Context) { - return getListFromContainer[T](DefaultContainer, ctx, key...) -} diff --git a/default_container_keyed_getters.go b/default_container_keyed_getters.go new file mode 100644 index 0000000..1bb7919 --- /dev/null +++ b/default_container_keyed_getters.go @@ -0,0 +1,15 @@ +package ore + +import ( + "context" +) + +// GetKeyed Retrieves an instance based on type and key (panics if no valid implementations) +func GetKeyed[T any](ctx context.Context, key ...KeyStringer) (T, context.Context) { + return getFromContainer[T](DefaultContainer, ctx, key...) +} + +// GetKeyedList Retrieves a list of instances based on type and key +func GetKeyedList[T any](ctx context.Context, key ...KeyStringer) ([]T, context.Context) { + return getListFromContainer[T](DefaultContainer, ctx, key...) +} diff --git a/default_container_unkeyed_getters.go b/default_container_unkeyed_getters.go new file mode 100644 index 0000000..9bc7169 --- /dev/null +++ b/default_container_unkeyed_getters.go @@ -0,0 +1,15 @@ +package ore + +import ( + "context" +) + +// Get Retrieves an instance based on type and key (panics if no valid implementations) +func Get[T any](ctx context.Context) (T, context.Context) { + return getFromContainer[T](DefaultContainer, ctx) +} + +// GetList Retrieves a list of instances based on type and key +func GetList[T any](ctx context.Context) ([]T, context.Context) { + return getListFromContainer[T](DefaultContainer, ctx) +} From bbd07da183994890023eee51e4a8e4ed7f0557e3 Mon Sep 17 00:00:00 2001 From: Firas Darwish Date: Fri, 15 Nov 2024 14:50:46 +0300 Subject: [PATCH 08/12] sep. keyed&unkeyed getters --- alias_test.go | 16 ++++++++-------- container_keyed_getters.go | 12 ++++++------ container_unkeyed_getters.go | 4 ++-- creator_test.go | 6 +++--- default_container_keyed_getters.go | 8 ++++---- default_container_keyed_registerers.go | 21 +++++++++++++++------ default_container_unkeyed_getters.go | 4 ++-- eager_singleton_test.go | 6 +++--- get_list_test.go | 2 +- get_test.go | 6 +++--- initializer_test.go | 6 +++--- internal_getters.go | 10 +++++----- registrars_placeholder_test.go | 14 +++++++------- 13 files changed, 62 insertions(+), 53 deletions(-) diff --git a/alias_test.go b/alias_test.go index 9c632e0..8280ba3 100644 --- a/alias_test.go +++ b/alias_test.go @@ -71,10 +71,10 @@ func TestAliasWithDifferentScope(t *testing.T) { ctx := context.Background() - person, ctx := Get[m.IPerson](ctx, module) + person, ctx := GetKeyed[m.IPerson](ctx, module) assert.Equal(t, person.(*m.Broker).Name, "Scoped") - personList, _ := GetList[m.IPerson](ctx, module) + personList, _ := GetKeyedList[m.IPerson](ctx, module) assert.Equal(t, len(personList), 3) } @@ -106,22 +106,22 @@ func TestAliasIsScopedByKeys(t *testing.T) { ctx := context.Background() - person1, ctx := Get[m.IPerson](ctx, "module1") // will return the m.Broker John + person1, ctx := GetKeyed[m.IPerson](ctx, "module1") // will return the m.Broker John assert.Equal(t, person1.(*m.Broker).Name, "John1") - personList1, ctx := GetList[m.IPerson](ctx, "module1") // will return all registered m.Broker and m.Trader + personList1, ctx := GetKeyedList[m.IPerson](ctx, "module1") // will return all registered m.Broker and m.Trader assert.Equal(t, len(personList1), 3) - person2, ctx := Get[m.IPerson](ctx, "module2") // will return the m.Broker John + person2, ctx := GetKeyed[m.IPerson](ctx, "module2") // will return the m.Broker John assert.Equal(t, person2.(*m.Broker).Name, "John2") - personList2, ctx := GetList[m.IPerson](ctx, "module2") // will return all registered m.Broker and m.Trader + personList2, ctx := GetKeyedList[m.IPerson](ctx, "module2") // will return all registered m.Broker and m.Trader assert.Equal(t, len(personList2), 2) - person3, ctx := Get[m.IPerson](ctx, "module3") // will return the m.Trader Mary + person3, ctx := GetKeyed[m.IPerson](ctx, "module3") // will return the m.Trader Mary assert.Equal(t, person3.(*m.Trader).Name, "Mary3") - personList3, ctx := GetList[m.IPerson](ctx, "module3") // will return all registered m.Broker and m.Trader + personList3, ctx := GetKeyedList[m.IPerson](ctx, "module3") // will return all registered m.Broker and m.Trader assert.Equal(t, len(personList3), 1) personListNoModule, _ := GetList[m.IPerson](ctx) // will return all registered m.Broker and m.Trader without keys diff --git a/container_keyed_getters.go b/container_keyed_getters.go index 30c8360..c5cb57b 100644 --- a/container_keyed_getters.go +++ b/container_keyed_getters.go @@ -4,12 +4,12 @@ import ( "context" ) -// GetFromContainer Retrieves an instance from the given container based on type and key (panics if no valid implementations) -func GetKeyedFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) (T, context.Context) { - return getFromContainer[T](con, ctx, key...) +// GetKeyedFromContainer Retrieves an instance from the given container based on type and key (panics if no valid implementations) +func GetKeyedFromContainer[T any](con *Container, ctx context.Context, key KeyStringer) (T, context.Context) { + return getFromContainer[T](con, ctx, key) } -// GetListFromContainer Retrieves a list of instances from the given container based on type and key -func GetKeyedListFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) ([]T, context.Context) { - return getListFromContainer[T](con, ctx, key...) +// GetKeyedListFromContainer Retrieves a list of instances from the given container based on type and key +func GetKeyedListFromContainer[T any](con *Container, ctx context.Context, key KeyStringer) ([]T, context.Context) { + return getListFromContainer[T](con, ctx, key) } diff --git a/container_unkeyed_getters.go b/container_unkeyed_getters.go index 13bf821..7181e8b 100644 --- a/container_unkeyed_getters.go +++ b/container_unkeyed_getters.go @@ -6,12 +6,12 @@ import ( // GetFromContainer Retrieves an instance from the given container based on type and key (panics if no valid implementations) func GetFromContainer[T any](con *Container, ctx context.Context) (T, context.Context) { - return getFromContainer[T](con, ctx) + return getFromContainer[T](con, ctx, nil) } // GetListFromContainer Retrieves a list of instances from the given container based on type and key func GetListFromContainer[T any](con *Container, ctx context.Context) ([]T, context.Context) { - return getListFromContainer[T](con, ctx) + return getListFromContainer[T](con, ctx, nil) } // TODO sep. to a file diff --git a/creator_test.go b/creator_test.go index 67315d4..831a895 100644 --- a/creator_test.go +++ b/creator_test.go @@ -75,7 +75,7 @@ func TestRegisterCreatorMultipleImplementationsKeyed(t *testing.T) { RegisterCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}) - counters, _ := GetList[interfaces.SomeCounter](context.Background(), "firas") + counters, _ := GetKeyedList[interfaces.SomeCounter](context.Background(), "firas") if got := len(counters); got != 2 { t.Errorf("got %v, expected %v", got, 2) @@ -162,7 +162,7 @@ func TestRegisterCreatorTransientState(t *testing.T) { func TestRegisterCreatorNilKeyOnRegistering(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterKeyedCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}, "", nil) + RegisterKeyedCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}, nil) }) } @@ -170,7 +170,7 @@ func TestRegisterCreatorNilKeyOnGetting(t *testing.T) { clearAll() RegisterKeyedCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}, "firas") assert.Panics(t, func() { - Get[interfaces.SomeCounter](context.Background(), nil) + GetKeyed[interfaces.SomeCounter](context.Background(), nil) }) } diff --git a/default_container_keyed_getters.go b/default_container_keyed_getters.go index 1bb7919..211abc3 100644 --- a/default_container_keyed_getters.go +++ b/default_container_keyed_getters.go @@ -5,11 +5,11 @@ import ( ) // GetKeyed Retrieves an instance based on type and key (panics if no valid implementations) -func GetKeyed[T any](ctx context.Context, key ...KeyStringer) (T, context.Context) { - return getFromContainer[T](DefaultContainer, ctx, key...) +func GetKeyed[T any](ctx context.Context, key KeyStringer) (T, context.Context) { + return getFromContainer[T](DefaultContainer, ctx, key) } // GetKeyedList Retrieves a list of instances based on type and key -func GetKeyedList[T any](ctx context.Context, key ...KeyStringer) ([]T, context.Context) { - return getListFromContainer[T](DefaultContainer, ctx, key...) +func GetKeyedList[T any](ctx context.Context, key KeyStringer) ([]T, context.Context) { + return getListFromContainer[T](DefaultContainer, ctx, key) } diff --git a/default_container_keyed_registerers.go b/default_container_keyed_registerers.go index 2042db0..60a99d5 100644 --- a/default_container_keyed_registerers.go +++ b/default_container_keyed_registerers.go @@ -4,31 +4,37 @@ import "context" // RegisterKeyedCreator Registers a lazily initialized value using a `Creator[T]` interface func RegisterKeyedCreator[T any](lifetime Lifetime, creator Creator[T], key KeyStringer) { + if key == nil { + panic(nilKey) + } registerCreatorToContainer[T](DefaultContainer, lifetime, creator, key) } // RegisterKeyedSingleton Registers an eagerly instantiated singleton value // To register an eagerly instantiated scoped value use [ProvideScopedValue] func RegisterKeyedSingleton[T comparable](impl T, key KeyStringer) { + if key == nil { + panic(nilKey) + } registerSingletonToContainer[T](DefaultContainer, impl, key) } // RegisterKeyedFunc Registers a lazily initialized value using an `Initializer[T]` function signature func RegisterKeyedFunc[T any](lifetime Lifetime, initializer Initializer[T], key KeyStringer) { + if key == nil { + panic(nilKey) + } registerFuncToContainer(DefaultContainer, lifetime, initializer, key) } -// RegisterKeyedAlias Registers an interface type to a concrete implementation. -// Allowing you to register the concrete implementation to the default container and later get the interface from it. -func RegisterKeyedAlias[TInterface, TImpl any]() { - registerAliasToContainer[TInterface, TImpl](DefaultContainer) -} - // RegisterKeyedPlaceholder registers a future value with Scoped lifetime. // This value will be injected in runtime using the [ProvideScopedValue] function. // Resolving objects which depend on this value will panic if the value has not been provided. // Placeholder with the same type and key can be registered only once. func RegisterKeyedPlaceholder[T comparable](key KeyStringer) { + if key == nil { + panic(nilKey) + } registerPlaceholderToContainer[T](DefaultContainer, key) } @@ -36,5 +42,8 @@ func RegisterKeyedPlaceholder[T comparable](key KeyStringer) { // This value will be available only to the default container. And the container can only resolve this value if // it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholder] function for more info. func ProvideKeyedScopedValue[T comparable](ctx context.Context, value T, key KeyStringer) context.Context { + if key == nil { + panic(nilKey) + } return provideScopedValueToContainer(DefaultContainer, ctx, value, key) } diff --git a/default_container_unkeyed_getters.go b/default_container_unkeyed_getters.go index 9bc7169..3b9e7d0 100644 --- a/default_container_unkeyed_getters.go +++ b/default_container_unkeyed_getters.go @@ -6,10 +6,10 @@ import ( // Get Retrieves an instance based on type and key (panics if no valid implementations) func Get[T any](ctx context.Context) (T, context.Context) { - return getFromContainer[T](DefaultContainer, ctx) + return getFromContainer[T](DefaultContainer, ctx, nil) } // GetList Retrieves a list of instances based on type and key func GetList[T any](ctx context.Context) ([]T, context.Context) { - return getListFromContainer[T](DefaultContainer, ctx) + return getListFromContainer[T](DefaultContainer, ctx, nil) } diff --git a/eager_singleton_test.go b/eager_singleton_test.go index ae0db61..ef58731 100644 --- a/eager_singleton_test.go +++ b/eager_singleton_test.go @@ -53,7 +53,7 @@ func TestRegisterEagerSingletonMultipleImplementationsKeyed(t *testing.T) { RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) - counters, _ := GetList[interfaces.SomeCounter](context.Background(), "firas") + counters, _ := GetKeyedList[interfaces.SomeCounter](context.Background(), "firas") if got := len(counters); got != 2 { t.Errorf("got %v, expected %v", got, 2) @@ -85,7 +85,7 @@ func TestRegisterEagerSingletonSingletonState(t *testing.T) { func TestRegisterEagerSingletonNilKeyOnRegistering(t *testing.T) { clearAll() assert.Panics(t, func() { - RegisterKeyedSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, nil, "") + RegisterKeyedSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, nil) }) } @@ -93,7 +93,7 @@ func TestRegisterEagerSingletonNilKeyOnGetting(t *testing.T) { clearAll() RegisterKeyedSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") assert.Panics(t, func() { - Get[interfaces.SomeCounter](context.Background(), nil, "") + GetKeyed[interfaces.SomeCounter](context.Background(), nil) }) } diff --git a/get_list_test.go b/get_list_test.go index 82d7ebf..cd38630 100644 --- a/get_list_test.go +++ b/get_list_test.go @@ -40,7 +40,7 @@ func TestGetListKeyed(t *testing.T) { RegisterKeyedCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, key) RegisterKeyedCreator[interfaces.SomeCounter](registrationType, &models.SimpleCounter{}, "Firas") - counters, _ := GetList[interfaces.SomeCounter](context.Background(), key) + counters, _ := GetKeyedList[interfaces.SomeCounter](context.Background(), key) if got := len(counters); got != 3 { t.Errorf("got %v, expected %v", got, 3) } diff --git a/get_test.go b/get_test.go index 9e284d9..5c9be4e 100644 --- a/get_test.go +++ b/get_test.go @@ -65,7 +65,7 @@ func TestGetKeyed(t *testing.T) { RegisterKeyedCreator[interfaces.SomeCounter](registrationType, &m.SimpleCounter{}, key) - c, _ := Get[interfaces.SomeCounter](context.Background(), key) + c, _ := GetKeyed[interfaces.SomeCounter](context.Background(), key) c.AddOne() c.AddOne() @@ -124,7 +124,7 @@ func TestGetResolvedSingletons(t *testing.T) { assert.Equal(t, 5, len(disposables)) //invoke X2 in "somekey" scope - _, _ = GetList[fmt.Stringer](ctx, "somekey") + _, _ = GetKeyedList[fmt.Stringer](ctx, "somekey") //Act //all invoked singleton would be returned whatever keys they are registered with @@ -218,7 +218,7 @@ func TestGetResolvedScopedInstances(t *testing.T) { assert.Equal(t, "S2", disposables[0].String()) //invoke the keyed service T1 - _, ctx = GetList[*m.DisposableService2](ctx, "module1") + _, ctx = GetKeyedList[*m.DisposableService2](ctx, "module1") //Act disposables = GetResolvedScopedInstances[m.Disposer](ctx) //S2, T1 diff --git a/initializer_test.go b/initializer_test.go index 1b4d505..5ae5d7d 100644 --- a/initializer_test.go +++ b/initializer_test.go @@ -89,7 +89,7 @@ func TestRegisterFuncMultipleImplementationsKeyed(t *testing.T) { return &models.SimpleCounter{}, ctx }) - counters, _ := GetList[interfaces.SomeCounter](context.Background(), "firas") + counters, _ := GetKeyedList[interfaces.SomeCounter](context.Background(), "firas") if got := len(counters); got != 2 { t.Errorf("got %v, expected %v", got, 2) @@ -184,7 +184,7 @@ func TestRegisterFuncNilKeyOnRegistering(t *testing.T) { assert.Panics(t, func() { RegisterKeyedFunc[interfaces.SomeCounter](Scoped, func(ctx context.Context) (interfaces.SomeCounter, context.Context) { return &models.SimpleCounter{}, ctx - }, "", nil) + }, nil) }) } @@ -195,7 +195,7 @@ func TestRegisterFuncNilKeyOnGetting(t *testing.T) { }, "firas") assert.Panics(t, func() { - Get[interfaces.SomeCounter](context.Background(), "", nil) + GetKeyed[interfaces.SomeCounter](context.Background(), "") }) } diff --git a/internal_getters.go b/internal_getters.go index 98736c7..36faf6c 100644 --- a/internal_getters.go +++ b/internal_getters.go @@ -43,9 +43,9 @@ func sortAndSelect[TInterface any](list []*concrete) []TInterface { return result } -func getFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) (T, context.Context) { +func getFromContainer[T any](con *Container, ctx context.Context, key KeyStringer) (T, context.Context) { pointerTypeName := getPointerTypeName[T]() - typeID := getTypeID(pointerTypeName, key...) + typeID := getTypeID(pointerTypeName, key) lastRegisteredResolver := con.getLastRegisteredResolver(typeID) if lastRegisteredResolver == nil { //not found, T is an alias @@ -62,7 +62,7 @@ func getFromContainer[T any](con *Container, ctx context.Context, key ...KeyStri } for i := count - 1; i >= 0; i-- { impl := implementations[i] - typeID = getTypeID(impl, key...) + typeID = getTypeID(impl, key) lastRegisteredResolver = con.getLastRegisteredResolver(typeID) if lastRegisteredResolver != nil { break @@ -76,7 +76,7 @@ func getFromContainer[T any](con *Container, ctx context.Context, key ...KeyStri return concrete.value.(T), ctx } -func getListFromContainer[T any](con *Container, ctx context.Context, key ...KeyStringer) ([]T, context.Context) { +func getListFromContainer[T any](con *Container, ctx context.Context, key KeyStringer) ([]T, context.Context) { inputPointerTypeName := getPointerTypeName[T]() con.lock.RLock() @@ -94,7 +94,7 @@ func getListFromContainer[T any](con *Container, ctx context.Context, key ...Key for i := 0; i < len(pointerTypeNames); i++ { pointerTypeName := pointerTypeNames[i] // generate type identifier - typeID := getTypeID(pointerTypeName, key...) + typeID := getTypeID(pointerTypeName, key) // try to get service resolver from container con.lock.RLock() diff --git a/registrars_placeholder_test.go b/registrars_placeholder_test.go index 478a6aa..f237fa8 100644 --- a/registrars_placeholder_test.go +++ b/registrars_placeholder_test.go @@ -94,15 +94,15 @@ func TestPlaceHolder_OverridePlaceHolder(t *testing.T) { ctx := ProvideKeyedScopedValue[*m.Trader](context.Background(), &m.Trader{Name: "John"}, "module2") //get the placeHolder value would success - trader, ctx := Get[*m.Trader](ctx, "module2") + trader, ctx := GetKeyed[*m.Trader](ctx, "module2") assert.Equal(t, "John", trader.Name) //replace the placeHolder value "John" with a new value "David" ctx = ProvideKeyedScopedValue[*m.Trader](ctx, &m.Trader{Name: "David"}, "module2") - trader, ctx = Get[*m.Trader](ctx, "module2") + trader, ctx = GetKeyed[*m.Trader](ctx, "module2") assert.Equal(t, "David", trader.Name) - traders, ctx := GetList[*m.Trader](ctx, "module2") + traders, ctx := GetKeyedList[*m.Trader](ctx, "module2") assert.Equal(t, 1, len(traders)) assert.Equal(t, "David", traders[0].Name) @@ -111,11 +111,11 @@ func TestPlaceHolder_OverridePlaceHolder(t *testing.T) { return &m.Trader{Name: "Mary"}, ctx }, "module2") - trader, ctx = Get[*m.Trader](ctx, "module2") + trader, ctx = GetKeyed[*m.Trader](ctx, "module2") assert.Equal(t, "Mary", trader.Name) //Get both the placeHolder value ("David") and the real resolver value ("Mary") - traders, ctx = GetList[*m.Trader](ctx, "module2") + traders, ctx = GetKeyedList[*m.Trader](ctx, "module2") assert.Equal(t, 2, len(traders)) //David and Mary assert.True(t, tradersListContainsName(traders, "David")) assert.True(t, tradersListContainsName(traders, "Mary")) @@ -124,11 +124,11 @@ func TestPlaceHolder_OverridePlaceHolder(t *testing.T) { ctx = ProvideKeyedScopedValue[*m.Trader](ctx, &m.Trader{Name: "Nathan"}, "module2") //the placeHolder value cannot override the real resolver value - trader, ctx = Get[*m.Trader](ctx, "module2") + trader, ctx = GetKeyed[*m.Trader](ctx, "module2") assert.Equal(t, "Mary", trader.Name) //but it replaces the old placeHolder value ("Nathan" will replace "David") - traders, _ = GetList[*m.Trader](ctx, "module2") + traders, _ = GetKeyedList[*m.Trader](ctx, "module2") assert.Equal(t, 2, len(traders)) //Nathan and Mary assert.True(t, tradersListContainsName(traders, "Nathan")) assert.True(t, tradersListContainsName(traders, "Mary")) From c8c253f12a453676ec90eba0906bf34817395cf4 Mon Sep 17 00:00:00 2001 From: Firas Darwish Date: Fri, 15 Nov 2024 14:57:40 +0300 Subject: [PATCH 09/12] nil check keyed --- container_keyed_getters.go | 6 +++ container_keyed_registerers.go | 22 +++++++--- container_unkeyed_getters.go | 56 ------------------------ default_container_keyed_getters.go | 6 +++ default_container_unkeyed_registerers.go | 7 --- shared_getters.go | 56 ++++++++++++++++++++++++ shared_registerers.go | 13 ++++++ 7 files changed, 96 insertions(+), 70 deletions(-) create mode 100644 shared_getters.go create mode 100644 shared_registerers.go diff --git a/container_keyed_getters.go b/container_keyed_getters.go index c5cb57b..cac9036 100644 --- a/container_keyed_getters.go +++ b/container_keyed_getters.go @@ -6,10 +6,16 @@ import ( // GetKeyedFromContainer Retrieves an instance from the given container based on type and key (panics if no valid implementations) func GetKeyedFromContainer[T any](con *Container, ctx context.Context, key KeyStringer) (T, context.Context) { + if key == nil { + panic(nilKey) + } return getFromContainer[T](con, ctx, key) } // GetKeyedListFromContainer Retrieves a list of instances from the given container based on type and key func GetKeyedListFromContainer[T any](con *Container, ctx context.Context, key KeyStringer) ([]T, context.Context) { + if key == nil { + panic(nilKey) + } return getListFromContainer[T](con, ctx, key) } diff --git a/container_keyed_registerers.go b/container_keyed_registerers.go index 411df86..015315f 100644 --- a/container_keyed_registerers.go +++ b/container_keyed_registerers.go @@ -6,32 +6,37 @@ import ( // RegisterKeyedCreatorToContainer Registers a lazily initialized value to the given container using a `Creator[T]` interface func RegisterKeyedCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T], key KeyStringer) { + if key == nil { + panic(nilKey) + } registerCreatorToContainer(con, lifetime, creator, key) } // RegisterKeyedSingletonToContainer Registers an eagerly instantiated singleton value to the given container. // To register an eagerly instantiated scoped value use [ProvideScopedValueToContainer] func RegisterKeyedSingletonToContainer[T comparable](con *Container, impl T, key KeyStringer) { + if key == nil { + panic(nilKey) + } registerSingletonToContainer(con, impl, key) } // RegisterKeyedFuncToContainer Registers a lazily initialized value to the given container using an `Initializer[T]` function signature func RegisterKeyedFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T], key KeyStringer) { + if key == nil { + panic(nilKey) + } registerFuncToContainer(con, lifetime, initializer, key) } -// TODO move to sep file -// RegisterAliasToContainer Registers an interface type to a concrete implementation in the given container. -// Allowing you to register the concrete implementation to the container and later get the interface from it. -func RegisterAliasToContainer[TInterface, TImpl any](con *Container) { - registerAliasToContainer[TInterface, TImpl](con) -} - // RegisterKeyedPlaceholderToContainer registers a future value with Scoped lifetime to the given container. // This value will be injected in runtime using the [ProvideScopedValue] function. // Resolving objects which depend on this value will panic if the value has not been provided. // Placeholder with the same type and key can be registered only once. func RegisterKeyedPlaceholderToContainer[T comparable](con *Container, key KeyStringer) { + if key == nil { + panic(nilKey) + } registerPlaceholderToContainer[T](con, key) } @@ -39,5 +44,8 @@ func RegisterKeyedPlaceholderToContainer[T comparable](con *Container, key KeySt // This value will be available only to the given container. And the container can only resolve this value if // it has the matching (type and key's) Placeholder registered. Checkout the [RegisterPlaceholderToContainer] function for more info. func ProvideKeyedScopedValueToContainer[T comparable](con *Container, ctx context.Context, value T, key KeyStringer) context.Context { + if key == nil { + panic(nilKey) + } return provideScopedValueToContainer(con, ctx, value, key) } diff --git a/container_unkeyed_getters.go b/container_unkeyed_getters.go index 7181e8b..de48931 100644 --- a/container_unkeyed_getters.go +++ b/container_unkeyed_getters.go @@ -13,59 +13,3 @@ func GetFromContainer[T any](con *Container, ctx context.Context) (T, context.Co func GetListFromContainer[T any](con *Container, ctx context.Context) ([]T, context.Context) { return getListFromContainer[T](con, ctx, nil) } - -// TODO sep. to a file -// GetResolvedSingletonsFromContainer retrieves a list of Singleton instances that implement the [TInterface] from the given container. -// See [GetResolvedSingletons] for more information. -func GetResolvedSingletonsFromContainer[TInterface any](con *Container) []TInterface { - return getResolvedSingletonsFromContainer[TInterface](con) -} - -// TODO separate to a file -// GetResolvedSingletons retrieves a list of Singleton instances that implement the [TInterface]. -// The returned instances are sorted by creation time (a.k.a the invocation order), the first one being the "most recently" created one. -// If an instance "A" depends on certain instances "B" and "C" then this function guarantee to return "B" and "C" before "A" in the list. -// It would return only the instances which had been resolved. Other lazy implementations which have never been invoked will not be returned. -// This function is useful for cleaning operations. -// -// Example: -// -// disposableSingletons := ore.GetResolvedSingletons[Disposer]() -// for _, disposable := range disposableSingletons { -// disposable.Dispose() -// } -func GetResolvedSingletons[TInterface any]() []TInterface { - return getResolvedSingletonsFromContainer[TInterface](DefaultContainer) -} - -// TODO separate to a file -// GetResolvedScopedInstances retrieves a list of Scoped instances that implement the [TInterface]. -// The returned instances are sorted by creation time (a.k.a the invocation order), the first one being the most recently created one. -// If an instance "A" depends on certain instances "B" and "C" then this function guarantee to return "B" and "C" before "A" in the list. -// It would return only the instances which had been resolved. Other lazy implementations which have never been invoked will not be returned. -// This function is useful for cleaning operations. -// -// Example: -// -// disposableInstances := ore.GetResolvedScopedInstances[Disposer](ctx) -// for _, disposable := range disposableInstances { -// disposable.Dispose() -// } -func GetResolvedScopedInstances[TInterface any](ctx context.Context) []TInterface { - contextKeyRepository, ok := ctx.Value(contextKeysRepositoryID).(contextKeysRepository) - if !ok { - return []TInterface{} - } - - list := []*concrete{} - - //filtering - for _, contextKey := range contextKeyRepository { - con := ctx.Value(contextKey).(*concrete) - if _, ok := con.value.(TInterface); ok { - list = append(list, con) - } - } - - return sortAndSelect[TInterface](list) -} diff --git a/default_container_keyed_getters.go b/default_container_keyed_getters.go index 211abc3..24a8cf5 100644 --- a/default_container_keyed_getters.go +++ b/default_container_keyed_getters.go @@ -6,10 +6,16 @@ import ( // GetKeyed Retrieves an instance based on type and key (panics if no valid implementations) func GetKeyed[T any](ctx context.Context, key KeyStringer) (T, context.Context) { + if key == nil { + panic(nilKey) + } return getFromContainer[T](DefaultContainer, ctx, key) } // GetKeyedList Retrieves a list of instances based on type and key func GetKeyedList[T any](ctx context.Context, key KeyStringer) ([]T, context.Context) { + if key == nil { + panic(nilKey) + } return getListFromContainer[T](DefaultContainer, ctx, key) } diff --git a/default_container_unkeyed_registerers.go b/default_container_unkeyed_registerers.go index 3de1e5b..1b5a1bc 100644 --- a/default_container_unkeyed_registerers.go +++ b/default_container_unkeyed_registerers.go @@ -18,13 +18,6 @@ func RegisterFunc[T any](lifetime Lifetime, initializer Initializer[T]) { registerFuncToContainer(DefaultContainer, lifetime, initializer, nil) } -// TODO move to separate file -// RegisterAlias Registers an interface type to a concrete implementation. -// Allowing you to register the concrete implementation to the default container and later get the interface from it. -func RegisterAlias[TInterface, TImpl any]() { - registerAliasToContainer[TInterface, TImpl](DefaultContainer) -} - // RegisterPlaceholder registers a future value with Scoped lifetime. // This value will be injected in runtime using the [ProvideScopedValue] function. // Resolving objects which depend on this value will panic if the value has not been provided. diff --git a/shared_getters.go b/shared_getters.go new file mode 100644 index 0000000..a099187 --- /dev/null +++ b/shared_getters.go @@ -0,0 +1,56 @@ +package ore + +import "context" + +// GetResolvedSingletonsFromContainer retrieves a list of Singleton instances that implement the [TInterface] from the given container. +// See [GetResolvedSingletons] for more information. +func GetResolvedSingletonsFromContainer[TInterface any](con *Container) []TInterface { + return getResolvedSingletonsFromContainer[TInterface](con) +} + +// GetResolvedSingletons retrieves a list of Singleton instances that implement the [TInterface]. +// The returned instances are sorted by creation time (a.k.a the invocation order), the first one being the "most recently" created one. +// If an instance "A" depends on certain instances "B" and "C" then this function guarantee to return "B" and "C" before "A" in the list. +// It would return only the instances which had been resolved. Other lazy implementations which have never been invoked will not be returned. +// This function is useful for cleaning operations. +// +// Example: +// +// disposableSingletons := ore.GetResolvedSingletons[Disposer]() +// for _, disposable := range disposableSingletons { +// disposable.Dispose() +// } +func GetResolvedSingletons[TInterface any]() []TInterface { + return getResolvedSingletonsFromContainer[TInterface](DefaultContainer) +} + +// GetResolvedScopedInstances retrieves a list of Scoped instances that implement the [TInterface]. +// The returned instances are sorted by creation time (a.k.a the invocation order), the first one being the most recently created one. +// If an instance "A" depends on certain instances "B" and "C" then this function guarantee to return "B" and "C" before "A" in the list. +// It would return only the instances which had been resolved. Other lazy implementations which have never been invoked will not be returned. +// This function is useful for cleaning operations. +// +// Example: +// +// disposableInstances := ore.GetResolvedScopedInstances[Disposer](ctx) +// for _, disposable := range disposableInstances { +// disposable.Dispose() +// } +func GetResolvedScopedInstances[TInterface any](ctx context.Context) []TInterface { + contextKeyRepository, ok := ctx.Value(contextKeysRepositoryID).(contextKeysRepository) + if !ok { + return []TInterface{} + } + + list := []*concrete{} + + //filtering + for _, contextKey := range contextKeyRepository { + con := ctx.Value(contextKey).(*concrete) + if _, ok := con.value.(TInterface); ok { + list = append(list, con) + } + } + + return sortAndSelect[TInterface](list) +} diff --git a/shared_registerers.go b/shared_registerers.go new file mode 100644 index 0000000..913385e --- /dev/null +++ b/shared_registerers.go @@ -0,0 +1,13 @@ +package ore + +// RegisterAlias Registers an interface type to a concrete implementation. +// Allowing you to register the concrete implementation to the default container and later get the interface from it. +func RegisterAlias[TInterface, TImpl any]() { + registerAliasToContainer[TInterface, TImpl](DefaultContainer) +} + +// RegisterAliasToContainer Registers an interface type to a concrete implementation in the given container. +// Allowing you to register the concrete implementation to the container and later get the interface from it. +func RegisterAliasToContainer[TInterface, TImpl any](con *Container) { + registerAliasToContainer[TInterface, TImpl](con) +} From 550d73341e9bcf6d8170903f8f8a42ca82890f8f Mon Sep 17 00:00:00 2001 From: Firas Darwish Date: Fri, 15 Nov 2024 15:00:37 +0300 Subject: [PATCH 10/12] nil slice declaration --- shared_getters.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared_getters.go b/shared_getters.go index a099187..e3ef1f0 100644 --- a/shared_getters.go +++ b/shared_getters.go @@ -42,7 +42,7 @@ func GetResolvedScopedInstances[TInterface any](ctx context.Context) []TInterfac return []TInterface{} } - list := []*concrete{} + var list []*concrete //filtering for _, contextKey := range contextKeyRepository { From 1011e30ea6b6517020c520e05111377b79b56119 Mon Sep 17 00:00:00 2001 From: Firas Darwish Date: Fri, 15 Nov 2024 15:05:40 +0300 Subject: [PATCH 11/12] fixed examples --- examples/placeholderdemo/main.go | 14 ++++++-------- examples/simple/main.go | 8 ++++---- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/examples/placeholderdemo/main.go b/examples/placeholderdemo/main.go index 5460b59..a536555 100644 --- a/examples/placeholderdemo/main.go +++ b/examples/placeholderdemo/main.go @@ -7,8 +7,6 @@ import ( "github.com/firasdarwish/ore" ) -type UserRole struct { -} type SomeService struct { someConfig string } @@ -16,13 +14,13 @@ type SomeService struct { func main() { //register SomeService which depends on "someConfig" ore.RegisterFunc[*SomeService](ore.Scoped, func(ctx context.Context) (*SomeService, context.Context) { - someConfig, ctx := ore.Get[string](ctx, "someConfig") + someConfig, ctx := ore.GetKeyed[string](ctx, "someConfig") return &SomeService{someConfig}, ctx }) - //someConfig is unknow at registration time + //someConfig is unknown at registration time //the value of "someConfig" depends on the future user's request - ore.RegisterPlaceholder[string]("someConfig") + ore.RegisterKeyedPlaceholder[string]("someConfig") //Seal registration, no further registration is allowed ore.Seal() @@ -36,11 +34,11 @@ func main() { //inject a different config depends on the request, userRole := ctx.Value("role").(string) if userRole == "admin" { - ctx = ore.ProvideScopedValue(ctx, "Admin config", "someConfig") + ctx = ore.ProvideKeyedScopedValue(ctx, "Admin config", "someConfig") } else if userRole == "supervisor" { - ctx = ore.ProvideScopedValue(ctx, "Supervisor config", "someConfig") + ctx = ore.ProvideKeyedScopedValue(ctx, "Supervisor config", "someConfig") } else if userRole == "user" { - ctx = ore.ProvideScopedValue(ctx, "Public user config", "someConfig") + ctx = ore.ProvideKeyedScopedValue(ctx, "Public user config", "someConfig") } service, _ := ore.Get[*SomeService](ctx) diff --git a/examples/simple/main.go b/examples/simple/main.go index 2840fbd..d554e75 100644 --- a/examples/simple/main.go +++ b/examples/simple/main.go @@ -8,12 +8,12 @@ import ( ) func main() { - ore.RegisterFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { + ore.RegisterKeyedFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { fmt.Println("NEWLY INITIALIZED FROM FUNC") return &mycounter{}, ctx }, "firas") - ore.RegisterFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { + ore.RegisterKeyedFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { fmt.Println("NEWLY INITIALIZED FROM FUNC") return &mycounter{}, ctx }, "darwish") @@ -27,11 +27,11 @@ func main() { fmt.Println("STARTED ...") - c, ctx := ore.Get[Counter](ctx, "firas") + c, ctx := ore.GetKeyed[Counter](ctx, "firas") c.AddOne() c.AddOne() - c, ctx = ore.Get[Counter](ctx, "darwish") + c, ctx = ore.GetKeyed[Counter](ctx, "darwish") c.AddOne() c.AddOne() From d82a8d1d783bd0873a24c364994250c477fd6a41 Mon Sep 17 00:00:00 2001 From: Firas Darwish Date: Fri, 15 Nov 2024 15:46:23 +0300 Subject: [PATCH 12/12] updated README.md and benchmarks --- README.md | 89 +++++++++++++++++++++--------------- benchmarks_test.go | 5 +- eager_singleton_test.go | 18 ++++---- examples/benchperf/README.md | 12 ++--- 4 files changed, 71 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 1001100..ba4f8c8 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,20 @@ the management of object lifetimes and the inversion of control in your applicat - **Concurrency-Safe**: Utilizes a mutex to ensure safe concurrent access to the container. + +- **Placeholder Service Registration**: Designed to simplify scenarios where certain dependencies cannot be resolved at the time of service registration but can be resolved later during runtime. + + +- **Isolated Containers**: Enables the creation of multiple isolated, modular containers to support more scalable and testable architectures, especially for Modular Monoliths. + + +- **Aliases**: A powerful way to register type mappings, allowing one type to be treated as another, typically an interface or a more abstract type. + + +- **Runtime Validation**: Allow for better error handling and validation during the startup or testing phases of an application (circular dependencies, lifetime misalignment, and missing dependencies). + + +- **Graceful Termination**: To ensure graceful application (or context) termination and proper cleanup of resources, including shutting down all resolved objects created during the application (or context) lifetime.
## Installation @@ -99,7 +113,7 @@ var c Counter c = &models.SimpleCounter{} // register -ore.RegisterEagerSingleton[Counter](c) +ore.RegisterSingleton[Counter](c) ctx := context.Background() @@ -152,19 +166,20 @@ ore.RegisterFunc[Counter](ore.Scoped, func(ctx context.Context) (Counter, contex //}) // Keyed service registration -//ore.RegisterFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { +//ore.RegisterKeyedFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { // return &models.SimpleCounter{}, ctx -//}, "name here", 1234) +//}, "key-here") ctx := context.Background() // retrieve c, ctx := ore.Get[Counter](ctx) + c.AddOne() c.AddOne() // Keyed service retrieval -//c, ctx := ore.Get[Counter](ctx, "name here", 1234) +//c, ctx := ore.GetKeyed[Counter](ctx, "key-here") // retrieve again c, ctx = ore.Get[Counter](ctx) @@ -217,18 +232,18 @@ The last registered implementation takes precedence, so you can register a mock ```go // register -ore.RegisterFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { +ore.RegisterKeyedFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) { return &models.SimpleCounter{}, ctx -}, "name here", 1234) +}, "key-here") -//ore.RegisterCreator[Counter](ore.Scoped, &models.SimpleCounter{}, "name here", 1234) +//ore.RegisterKeyedCreator[Counter](ore.Scoped, &models.SimpleCounter{}, "key-here") -//ore.RegisterEagerSingleton[Counter](&models.SimpleCounter{}, "name here", 1234) +//ore.RegisterKeyedSingleton[Counter](&models.SimpleCounter{}, "key-here") ctx := context.Background() // Keyed service retrieval -c, ctx := ore.Get[Counter](ctx, "name here", 1234) +c, ctx := ore.GetKeyed[Counter](ctx, "key-here") c.AddOne() // prints out: `TOTAL: 1` @@ -321,9 +336,9 @@ Here how Ore can help you: type Shutdowner interface { Shutdown() } -ore.RegisterEagerSingleton(&Logger{}) //*Logger implements Shutdowner -ore.RegisterEagerSingleton(&SomeRepository{}) //*SomeRepository implements Shutdowner -ore.RegisterEagerSingleton(&SomeService{}, "some_module") //*SomeService implements Shutdowner +ore.RegisterSingleton(&Logger{}) //*Logger implements Shutdowner +ore.RegisterSingleton(&SomeRepository{}) //*SomeRepository implements Shutdowner +ore.RegisterKeyedSingleton(&SomeService{}, "some_module") //*SomeService implements Shutdowner //On application termination, Ore can help to retrieve all the singletons implementation //of the `Shutdowner` interface. @@ -392,17 +407,17 @@ The `ore.GetResolvedScopedInstances[TInterface](context)` function returns a lis ### Multiple Containers (a.k.a Modules) -| DefaultContainer | Custom container | -|------------------|------------------| -| Get | GetFromContainer | -| GetList | GetListFromContainer | +| DefaultContainer | Custom container | +|-----------------------|------------------------------------| +| Get | GetFromContainer | +| GetList | GetListFromContainer | | GetResolvedSingletons | GetResolvedSingletonsFromContainer | -| RegisterAlias | RegisterAliasToContainer | -| RegisterEagerSingleton | RegisterEagerSingletonToContainer | -| RegisterCreator | RegisterCreatorToContainer | -| RegisterFunc | RegisterFuncToContainer | -| RegisterPlaceHolder | RegisterPlaceHolderToContainer | -| ProvideScopedValue | ProvideScopedValueToContainer | +| RegisterAlias | RegisterAliasToContainer | +| RegisterSingleton | RegisterSingletonToContainer | +| RegisterCreator | RegisterCreatorToContainer | +| RegisterFunc | RegisterFuncToContainer | +| RegisterPlaceholder | RegisterPlaceholderToContainer | +| ProvideScopedValue | ProvideScopedValueToContainer | Most of time you only need the Default Container. In rare use case such as the Modular Monolith Architecture, you might want to use multiple containers, one per module. Ore provides minimum support for "module" in this case: @@ -439,13 +454,13 @@ A common scenario is that your "Service" depends on something which you couldn't ```go //register SomeService which depends on "someConfig" ore.RegisterFunc[*SomeService](ore.Scoped, func(ctx context.Context) (*SomeService, context.Context) { - someConfig, ctx := ore.Get[string](ctx, "someConfig") + someConfig, ctx := ore.GetKeyed[string](ctx, "someConfig") return &SomeService{someConfig}, ctx }) //someConfig is unknow at registration time because //this value depends on the future user's request -ore.RegisterPlaceHolder[string]("someConfig") +ore.RegisterKeyedPlaceholder[string]("someConfig") //a new request arrive ctx := context.Background() @@ -455,14 +470,14 @@ ctx = context.WithValue(ctx, "role", "admin") //inject a different somConfig value depending on the request's content userRole := ctx.Value("role").(string) if userRole == "admin" { - ctx = ore.ProvideScopedValue(ctx, "Admin config", "someConfig") + ctx = ore.ProvideKeyedScopedValue(ctx, "Admin config", "someConfig") } else if userRole == "supervisor" { - ctx = ore.ProvideScopedValue(ctx, "Supervisor config", "someConfig") + ctx = ore.ProvideKeyedScopedValue(ctx, "Supervisor config", "someConfig") } else if userRole == "user" { if (isAuthenticatedUser) { - ctx = ore.ProvideScopedValue(ctx, "Public user config", "someConfig") + ctx = ore.ProvideKeyedScopedValue(ctx, "Private user config", "someConfig") } else { - ctx = ore.ProvideScopedValue(ctx, "Private user config", "someConfig") + ctx = ore.ProvideKeyedScopedValue(ctx, "Public user config", "someConfig") } } @@ -473,7 +488,7 @@ fmt.Println(service.someConfig) //"Admin config" ([See full codes here](./examples/placeholderdemo/main.go)) -- `ore.RegisterPlaceHolder[T](key...)` registers a future value with Scoped lifetime. +- `ore.RegisterPlaceholder[T](key...)` registers a future value with Scoped lifetime. - This value will be injected in runtime using the `ProvideScopedValue` function. - Resolving objects which depend on this value will panic if the value has not been provided. @@ -530,15 +545,15 @@ goos: windows goarch: amd64 pkg: github.com/firasdarwish/ore cpu: 13th Gen Intel(R) Core(TM) i9-13900H -BenchmarkRegisterFunc-20 5706694 196.9 ns/op -BenchmarkRegisterCreator-20 6283534 184.5 ns/op -BenchmarkRegisterEagerSingleton-20 5146953 211.5 ns/op -BenchmarkInitialGet-20 3440072 352.1 ns/op -BenchmarkGet-20 9806043 121.8 ns/op -BenchmarkInitialGetList-20 1601787 747.9 ns/op -BenchmarkGetList-20 4237449 282.1 ns/op +BenchmarkRegisterFunc-20 5612482 214.6 ns/op +BenchmarkRegisterCreator-20 6498038 174.1 ns/op +BenchmarkRegisterSingleton-20 5474991 259.1 ns/op +BenchmarkInitialGet-20 2297595 514.3 ns/op +BenchmarkGet-20 9389530 122.1 ns/op +BenchmarkInitialGetList-20 1000000 1072 ns/op +BenchmarkGetList-20 3970850 301.7 ns/op PASS -ok github.com/firasdarwish/ore 11.427s +ok github.com/firasdarwish/ore 10.883s ``` Checkout also [examples/benchperf/README.md](examples/benchperf/README.md) diff --git a/benchmarks_test.go b/benchmarks_test.go index 0f63f1b..e28c401 100644 --- a/benchmarks_test.go +++ b/benchmarks_test.go @@ -27,7 +27,7 @@ func BenchmarkRegisterCreator(b *testing.B) { } } -func BenchmarkRegisterEagerSingleton(b *testing.B) { +func BenchmarkRegisterSingleton(b *testing.B) { clearAll() b.ResetTimer() @@ -70,6 +70,8 @@ func BenchmarkGet(b *testing.B) { RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) Seal() Validate() + DefaultContainer.DisableValidation = true + ctx := context.Background() b.ResetTimer() @@ -111,6 +113,7 @@ func BenchmarkGetList(b *testing.B) { RegisterCreator[interfaces.SomeCounter](Scoped, &models.SimpleCounter{}) Seal() Validate() + DefaultContainer.DisableValidation = true ctx := context.Background() b.ResetTimer() diff --git a/eager_singleton_test.go b/eager_singleton_test.go index ef58731..76216b2 100644 --- a/eager_singleton_test.go +++ b/eager_singleton_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestRegisterEagerSingleton(t *testing.T) { +func TestRegisterSingleton(t *testing.T) { clearAll() RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) @@ -24,14 +24,14 @@ func TestRegisterEagerSingleton(t *testing.T) { } } -func TestRegisterEagerSingletonNilImplementation(t *testing.T) { +func TestRegisterSingletonNilImplementation(t *testing.T) { clearAll() assert.Panics(t, func() { RegisterSingleton[interfaces.SomeCounter](nil) }) } -func TestRegisterEagerSingletonMultipleImplementations(t *testing.T) { +func TestRegisterSingletonMultipleImplementations(t *testing.T) { clearAll() RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) @@ -45,7 +45,7 @@ func TestRegisterEagerSingletonMultipleImplementations(t *testing.T) { } } -func TestRegisterEagerSingletonMultipleImplementationsKeyed(t *testing.T) { +func TestRegisterSingletonMultipleImplementationsKeyed(t *testing.T) { clearAll() RegisterKeyedSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") @@ -60,7 +60,7 @@ func TestRegisterEagerSingletonMultipleImplementationsKeyed(t *testing.T) { } } -func TestRegisterEagerSingletonSingletonState(t *testing.T) { +func TestRegisterSingletonSingletonState(t *testing.T) { clearAll() RegisterSingleton[interfaces.SomeCounter](&models.SimpleCounter{}) @@ -82,14 +82,14 @@ func TestRegisterEagerSingletonSingletonState(t *testing.T) { } } -func TestRegisterEagerSingletonNilKeyOnRegistering(t *testing.T) { +func TestRegisterSingletonNilKeyOnRegistering(t *testing.T) { clearAll() assert.Panics(t, func() { RegisterKeyedSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, nil) }) } -func TestRegisterEagerSingletonNilKeyOnGetting(t *testing.T) { +func TestRegisterSingletonNilKeyOnGetting(t *testing.T) { clearAll() RegisterKeyedSingleton[interfaces.SomeCounter](&models.SimpleCounter{}, "firas") assert.Panics(t, func() { @@ -97,7 +97,7 @@ func TestRegisterEagerSingletonNilKeyOnGetting(t *testing.T) { }) } -func TestRegisterEagerSingletonGeneric(t *testing.T) { +func TestRegisterSingletonGeneric(t *testing.T) { clearAll() RegisterSingleton[interfaces.SomeCounterGeneric[uint]](&models.CounterGeneric[uint]{}) @@ -112,7 +112,7 @@ func TestRegisterEagerSingletonGeneric(t *testing.T) { } } -func TestRegisterEagerSingletonMultipleGenericImplementations(t *testing.T) { +func TestRegisterSingletonMultipleGenericImplementations(t *testing.T) { clearAll() RegisterSingleton[interfaces.SomeCounterGeneric[uint]](&models.CounterGeneric[uint]{}) diff --git a/examples/benchperf/README.md b/examples/benchperf/README.md index 0783bfe..c139466 100644 --- a/examples/benchperf/README.md +++ b/examples/benchperf/README.md @@ -57,15 +57,15 @@ DGa -.implement..-> G On my machine, Ore always perform faster and use less memory than Samber/Do: ```text -goos: linux +goos: windows goarch: amd64 pkg: examples/benchperf -cpu: 13th Gen Intel(R) Core(TM) i7-1365U -Benchmark_Ore-12 409480 2509 ns/op 2089 B/op 57 allocs/op -Benchmark_OreNoValidation-12 671000 1699 ns/op 1080 B/op 30 allocs/op -Benchmark_SamberDo-12 218361 4825 ns/op 2184 B/op 70 allocs/op +cpu: 13th Gen Intel(R) Core(TM) i9-13900H +Benchmark_Ore-20 448519 2427 ns/op 2233 B/op 57 allocs/op +Benchmark_OreNoValidation-20 814785 1477 ns/op 1080 B/op 30 allocs/op +Benchmark_SamberDo-20 246958 4891 ns/op 2184 B/op 70 allocs/op PASS -ok examples/benchperf 4.222s +ok examples/benchperf 4.016s ``` As any benchmarks, please take these number "relatively" as a general idea: