initial commit
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user