generic-di/injector.go
2025-06-22 20:12:29 +02:00

68 lines
1.7 KiB
Go

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) {
creatorMutex.Lock()
defer creatorMutex.Unlock()
creators[getSelector[T]()] = func() any {
return creator()
}
}
// Inject gets or create a Instance of the Struct used the Injectable constructor Function
func Inject[T any](identifier ...string) T {
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 instances[instanceSelector].(T)
}
func Destroy[T any](identifier ...string) {
instanceMutex.Lock()
defer instanceMutex.Unlock()
instanceSelector := getSelector[T](identifier...)
delete(instances, instanceSelector)
}
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)
}