You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
74 lines
1.8 KiB
Go
74 lines
1.8 KiB
Go
package sl
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
)
|
|
|
|
type provider struct {
|
|
initialized bool
|
|
service Service
|
|
}
|
|
|
|
type ServiceLocator struct {
|
|
providers map[string]*provider
|
|
hooks map[string][]Service
|
|
}
|
|
|
|
type Service interface {
|
|
Initialize(l *ServiceLocator) error
|
|
}
|
|
|
|
func New() *ServiceLocator {
|
|
return &ServiceLocator{
|
|
providers: map[string]*provider{},
|
|
hooks: map[string][]Service{},
|
|
}
|
|
}
|
|
|
|
func getTypeName[T any]() string {
|
|
var v T
|
|
return fmt.Sprintf(`%T`, &v)[1:]
|
|
}
|
|
|
|
// Inject will set the implementation for "S" to "value" (the service will be initialized when needed after all of its dependencies)
|
|
func Inject[S Service](l *ServiceLocator, value S) {
|
|
key := getTypeName[S]()
|
|
log.Printf(`injecting value of type %T for interface %s`, value, key)
|
|
|
|
l.providers[key] = &provider{false, value}
|
|
}
|
|
|
|
// InjectValue will set the implementation for "S" to "value" and mark this service as already initialized (as this is just a constant)
|
|
func InjectValue[S Service](l *ServiceLocator, value S) S {
|
|
key := getTypeName[S]()
|
|
log.Printf(`injecting value of type %T for interface %s`, value, key)
|
|
|
|
l.providers[key] = &provider{true, value}
|
|
return value
|
|
}
|
|
|
|
// Use will retrive from the service locator the implementation set for the type "T" and initialize the service if yet to be initialized
|
|
func Use[T Service](l *ServiceLocator) (T, error) {
|
|
provider, ok := l.providers[getTypeName[T]()]
|
|
if !ok {
|
|
var zero T
|
|
return zero, fmt.Errorf(`no injected value for type "%T"`, zero)
|
|
}
|
|
|
|
if provider.initialized {
|
|
service := provider.service.(T)
|
|
return service, nil
|
|
}
|
|
|
|
log.Printf(`initializing %T`, provider.service)
|
|
if err := provider.service.Initialize(l); err != nil {
|
|
var zero T
|
|
return zero, err
|
|
}
|
|
|
|
provider.initialized = true
|
|
service := provider.service.(T)
|
|
return service, nil
|
|
}
|