Skip to content

Instantly share code, notes, and snippets.

@dezren39
Last active March 2, 2024 00:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dezren39/d98e83ee763011cbf62313b95678b230 to your computer and use it in GitHub Desktop.
Save dezren39/d98e83ee763011cbf62313b95678b230 to your computer and use it in GitHub Desktop.
// https://github.com/samber/do/issues/30#issuecomment-1705616069
// https://play.golang.org/p/yHLzoV9To_5
package main
import (
"errors"
"fmt"
"sync"
)
type key[T any] struct{ name string }
type provider[T any] func() (T, error)
var services = make(map[any]any)
var servicesMutex sync.RWMutex
func ProvideNamed[T any](name string, p provider[T]) {
servicesMutex.Lock()
defer servicesMutex.Unlock()
services[key[T]{name}] = p
}
func ProvideNamedValue[T any](name string, v T) {
servicesMutex.Lock()
defer servicesMutex.Unlock()
services[key[T]{name}] = v
}
func InvokeNamed[T any](name string) (T, error) {
servicesMutex.RLock()
defer servicesMutex.RUnlock()
if provider, ok := services[key[T]{name}].(provider[T]); ok {
return provider()
}
if value, ok := services[key[T]{name}].(T); ok {
return value, nil
}
return empty[T](), errors.New("not found")
}
func Provide[T any](p provider[T]) {
ProvideNamed[T]("", p)
}
func ProvideValue[T any](v T) {
ProvideNamedValue[T]("", v)
}
func Invoke[T any]() (T, error) {
return InvokeNamed[T]("")
}
func empty[T any]() (t T) {
return
}
func main() {
Provide(func() (int, error) {
return 42, nil
})
ProvideValue("Hello, world!")
if val, err := Invoke[int](); err == nil {
fmt.Println("Invoke[int]():", val)
} else {
fmt.Println("Invoke[int]():", err)
}
if val, err := Invoke[string](); err == nil {
fmt.Println("Invoke[string]():", val)
} else {
fmt.Println("Invoke[string]():", err)
}
type person struct {
name string
}
Provide(func() (person, error) {
return person{"Drew"}, nil
})
ProvideNamedValue("customPerson", person{"Drewry"})
if val, err := Invoke[person](); err == nil {
fmt.Println("Invoke[person]():", val.name)
} else {
fmt.Println("Invoke[person]():", err)
}
if val, err := InvokeNamed[person]("customPerson"); err == nil {
fmt.Println("InvokeNamed[person](\"customPerson\"):", val.name)
} else {
fmt.Println("InvokeNamed[person](\"customPerson\"):", err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment