92 lines
2.0 KiB
Go
92 lines
2.0 KiB
Go
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) getSelector(typ reflect.Type, identifier ...string) string {
|
|
typeName := typ.String()
|
|
additionalKey := strings.Join(identifier, "_")
|
|
return fmt.Sprintf("%s_%s", typeName, additionalKey)
|
|
}
|