- App-scoped typed Publish/Lookup with duplicate-provider errors - Set plugin IDs before Register so HasPlugin sees the full set - Greeter uses pact.OptionalMessage without importing optional
61 lines
1.2 KiB
Go
61 lines
1.2 KiB
Go
package backpack
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"sync"
|
|
)
|
|
|
|
// Registry is an app-scoped typed service catalog. It has no process-global state.
|
|
type Registry struct {
|
|
mu sync.RWMutex
|
|
m map[reflect.Type]any
|
|
}
|
|
|
|
// NewRegistry returns an empty service registry.
|
|
func NewRegistry() *Registry {
|
|
return &Registry{m: make(map[reflect.Type]any)}
|
|
}
|
|
|
|
// Publish stores value under the concrete type argument T. Publishing the
|
|
// same T twice is an error.
|
|
func (r *Registry) Publish[T any](value T) error {
|
|
if r == nil {
|
|
return fmt.Errorf("backpack: registry is nil")
|
|
}
|
|
if any(value) == nil {
|
|
return fmt.Errorf("backpack: publish nil service")
|
|
}
|
|
key := reflect.TypeFor[T]()
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
if r.m == nil {
|
|
r.m = make(map[reflect.Type]any)
|
|
}
|
|
if _, exists := r.m[key]; exists {
|
|
return fmt.Errorf("backpack: duplicate provider for %s", key)
|
|
}
|
|
r.m[key] = value
|
|
return nil
|
|
}
|
|
|
|
// Lookup returns the service published under T, or (zero, false).
|
|
func (r *Registry) Lookup[T any]() (T, bool) {
|
|
var zero T
|
|
if r == nil {
|
|
return zero, false
|
|
}
|
|
key := reflect.TypeFor[T]()
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
v, ok := r.m[key]
|
|
if !ok {
|
|
return zero, false
|
|
}
|
|
got, ok := v.(T)
|
|
if !ok {
|
|
return zero, false
|
|
}
|
|
return got, true
|
|
}
|