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.
website/sl/sl.go

74 lines
1.8 KiB
Go

2 years ago
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
}