Compare commits
No commits in common. "main" and "v1.4.0" have entirely different histories.
103
container.go
103
container.go
@ -1,103 +0,0 @@
|
||||
package di
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type container struct {
|
||||
mu sync.RWMutex
|
||||
creators map[string]func() any
|
||||
instances map[string]any
|
||||
}
|
||||
|
||||
var globalContainer *container
|
||||
var once sync.Once
|
||||
|
||||
func getContainer() *container {
|
||||
once.Do(func() {
|
||||
globalContainer = &container{
|
||||
mu: sync.RWMutex{},
|
||||
creators: make(map[string]func() any),
|
||||
instances: make(map[string]any),
|
||||
}
|
||||
})
|
||||
return globalContainer
|
||||
}
|
||||
|
||||
func (c *container) injectable(typ reflect.Type, creator func() any) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
selector := c.getSelector(typ)
|
||||
c.creators[selector] = creator
|
||||
}
|
||||
|
||||
func (c *container) replace(typ reflect.Type, creator func() any, identifier ...string) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
selector := c.getSelector(typ)
|
||||
instanceSelector := c.getSelector(typ, identifier...)
|
||||
c.creators[selector] = creator
|
||||
createdInstance := creator()
|
||||
c.instances[instanceSelector] = createdInstance
|
||||
}
|
||||
|
||||
func (c *container) inject(typ reflect.Type, identifier ...string) (any, bool) {
|
||||
instanceSelector := c.getSelector(typ, identifier...)
|
||||
|
||||
c.mu.RLock()
|
||||
if instance, ok := c.instances[instanceSelector]; ok {
|
||||
c.mu.RUnlock()
|
||||
return instance, true
|
||||
}
|
||||
c.mu.RUnlock()
|
||||
|
||||
c.mu.RLock()
|
||||
if instance, ok := c.instances[instanceSelector]; ok {
|
||||
c.mu.RUnlock()
|
||||
return instance, true
|
||||
}
|
||||
c.mu.RUnlock()
|
||||
|
||||
selector := c.getSelector(typ)
|
||||
creator, creatorExists := c.creators[selector]
|
||||
if !creatorExists {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
createdInstance := creator()
|
||||
c.mu.Lock()
|
||||
c.instances[instanceSelector] = createdInstance
|
||||
c.mu.Unlock()
|
||||
return createdInstance, true
|
||||
}
|
||||
|
||||
func (c *container) destroy(typ reflect.Type, identifier ...string) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
instanceSelector := c.getSelector(typ, identifier...)
|
||||
delete(c.instances, instanceSelector)
|
||||
}
|
||||
|
||||
func (c *container) destroyAllMatching(match func(string) bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for key := range c.instances {
|
||||
if match(key) {
|
||||
delete(c.instances, key)
|
||||
}
|
||||
}
|
||||
println("")
|
||||
}
|
||||
|
||||
func (c *container) getSelector(typ reflect.Type, identifier ...string) string {
|
||||
typeName := typ.String()
|
||||
additionalKey := strings.Join(identifier, "_")
|
||||
return fmt.Sprintf("%s_%s", additionalKey, typeName)
|
||||
}
|
||||
78
injector.go
78
injector.go
@ -1,41 +1,83 @@
|
||||
package di
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var creatorMutex = sync.Mutex{}
|
||||
var instanceMutex = sync.Mutex{}
|
||||
var creators = make(map[string]func() any)
|
||||
var instances = make(map[string]any)
|
||||
|
||||
// Injectable marks a constructor Function of a Struct for DI
|
||||
func Injectable[T any](creator func() T) {
|
||||
typ := reflect.TypeOf((*T)(nil)).Elem()
|
||||
getContainer().injectable(typ, func() any { return creator() })
|
||||
creatorMutex.Lock()
|
||||
defer creatorMutex.Unlock()
|
||||
creators[getSelector[T]()] = func() any {
|
||||
return creator()
|
||||
}
|
||||
}
|
||||
|
||||
func Replace[T any](creator func() T, identifier ...string) {
|
||||
typ := reflect.TypeOf((*T)(nil)).Elem()
|
||||
getContainer().replace(typ, func() any { return creator() })
|
||||
}
|
||||
|
||||
func ReplaceInstance[T any](instance T, identifier ...string) {
|
||||
Replace(func() T { return instance }, identifier...)
|
||||
Injectable(creator)
|
||||
selector := getSelector[T]()
|
||||
instanceSelector := getSelector[T](identifier...)
|
||||
cre, creatorExists := creators[selector]
|
||||
if !creatorExists {
|
||||
return
|
||||
}
|
||||
createdInstance, instanceCreated := cre().(T)
|
||||
if instanceCreated {
|
||||
instanceMutex.Lock()
|
||||
defer instanceMutex.Unlock()
|
||||
instances[instanceSelector] = createdInstance
|
||||
}
|
||||
}
|
||||
|
||||
// Inject gets or create a Instance of the Struct used the Injectable constructor Function
|
||||
func Inject[T any](identifier ...string) T {
|
||||
var result T
|
||||
typ := reflect.TypeOf((*T)(nil)).Elem()
|
||||
if instance, ok := getContainer().inject(typ, identifier...); ok {
|
||||
if result, ok = instance.(T); ok {
|
||||
return result
|
||||
var nilResult T
|
||||
selector := getSelector[T]()
|
||||
instanceSelector := getSelector[T](identifier...)
|
||||
_, instanceExists := instances[instanceSelector].(T)
|
||||
if !instanceExists {
|
||||
creator, creatorExists := creators[selector]
|
||||
if !creatorExists {
|
||||
return nilResult
|
||||
}
|
||||
createdInstance, instanceCreated := creator().(T)
|
||||
if instanceCreated {
|
||||
instanceMutex.Lock()
|
||||
defer instanceMutex.Unlock()
|
||||
instance, instanceExists := instances[instanceSelector].(T)
|
||||
if instanceExists {
|
||||
return instance
|
||||
}
|
||||
instances[instanceSelector] = createdInstance
|
||||
}
|
||||
}
|
||||
return result
|
||||
return instances[instanceSelector].(T)
|
||||
}
|
||||
|
||||
func Destroy[T any](identifier ...string) {
|
||||
typ := reflect.TypeOf((*T)(nil)).Elem()
|
||||
getContainer().destroy(typ, identifier...)
|
||||
instanceMutex.Lock()
|
||||
defer instanceMutex.Unlock()
|
||||
instanceSelector := getSelector[T](identifier...)
|
||||
delete(instances, instanceSelector)
|
||||
}
|
||||
|
||||
func DestroyAllMatching(match func(string) bool) {
|
||||
getContainer().destroyAllMatching(match)
|
||||
func getSelector[T any](identifier ...string) string {
|
||||
var def T
|
||||
typeName := ""
|
||||
typeOf := reflect.TypeOf(def)
|
||||
if typeOf != nil {
|
||||
typeName = typeOf.String()
|
||||
} else {
|
||||
typeName = reflect.TypeOf((*T)(nil)).Elem().String()
|
||||
}
|
||||
additionalKey := strings.Join(identifier, "_")
|
||||
return fmt.Sprintf("%s_%s", typeName, additionalKey)
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ package di_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
di "git.apihub24.de/admin/generic-di"
|
||||
@ -117,9 +116,6 @@ func (ctx *messageService) GetTextServiceID() string {
|
||||
}
|
||||
|
||||
func TestInject(t *testing.T) {
|
||||
// testMutex.Lock()
|
||||
// defer testMutex.Unlock()
|
||||
|
||||
msg := newMessageService()
|
||||
println(msg.texts.Greeting())
|
||||
if msg.texts.Greeting() != "Hello Markus" {
|
||||
@ -128,9 +124,6 @@ func TestInject(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInject_Duplicate(t *testing.T) {
|
||||
// testMutex.Lock()
|
||||
// defer testMutex.Unlock()
|
||||
|
||||
msg1 := newMessageService()
|
||||
msg2 := newMessageService()
|
||||
println(msg1.texts.Greeting())
|
||||
@ -199,26 +192,6 @@ func TestOverwriteInjectable(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverwriteInjectableInstance(t *testing.T) {
|
||||
basic := di.Inject[overridableService]()
|
||||
basicID := basic.GetInstanceID()
|
||||
di.ReplaceInstance(newBasicOverridableServiceMock())
|
||||
basic = di.Inject[overridableService]()
|
||||
if basic.GetInstanceID() == basicID {
|
||||
t.Errorf("basic and newOne are the same instance")
|
||||
}
|
||||
if basic.GetValue() != "i am mock" {
|
||||
t.Errorf("service not overwritten")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestroyMatching(t *testing.T) {
|
||||
_ = di.Inject[greetingService]("abc")
|
||||
_ = di.Inject[greetingService]("def")
|
||||
_ = di.Inject[greetingService]("abc_def")
|
||||
di.DestroyAllMatching(func(key string) bool { return strings.HasPrefix(key, "abc") })
|
||||
}
|
||||
|
||||
func TestDestroy(t *testing.T) {
|
||||
_ = di.Inject[textService]("a")
|
||||
di.Destroy[textService]("a")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user