From ee8768ec4ce5d0a040380d312c1e031ae876cc7b Mon Sep 17 00:00:00 2001 From: Alan Braithwaite Date: Sat, 4 Jan 2025 11:52:42 -0800 Subject: [PATCH 1/3] add options to loader --- loader/loader.go | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/loader/loader.go b/loader/loader.go index f34e7cf..c0e5635 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -1,6 +1,7 @@ package loader import ( + "errors" "fmt" "os" "reflect" @@ -32,17 +33,17 @@ func LoadConfig(bts []byte, cfg any) error { return nil } -type Builder[T any] interface { - Configure() (T, error) +type Builder[O, T any] interface { + Configure(...func(O)) (T, error) } -type Registry[T any] struct { - m map[string]func() Builder[T] +type Registry[O, T any] struct { + m map[string]func() Builder[O, T] sync.RWMutex } var registry = struct { - // map[typeString]registry[T] where T is variadic and typeString is: + // map[typeString]registry[O, T] where T is variadic and typeString is: // reflect.TypeOf(T).String() m map[string]any sync.RWMutex @@ -63,7 +64,7 @@ func loadTypeReg(typ string) (any, error) { // Register registers a factory method for a type T with the given type name. T // is typically an interface that is implmented by the struct of type given by // the name. -func Register[T any](name string, factory func() Builder[T]) { +func Register[O, T any](name string, factory func() Builder[O, T]) { registry.Lock() defer registry.Unlock() @@ -73,27 +74,28 @@ func Register[T any](name string, factory func() Builder[T]) { typStr := reflect.TypeOf(typ).String() typReg, ok := registry.m[typStr] if !ok { - typReg = &Registry[T]{ - m: make(map[string]func() Builder[T]), + typReg = &Registry[O, T]{ + m: make(map[string]func() Builder[O, T]), } registry.m[typStr] = typReg } - registryForType := typReg.(*Registry[T]) + registryForType := typReg.(*Registry[O, T]) registryForType.m[name] = factory } -type Loader[T any] struct { - Builder[T] +// Loader is a struct which can dyanmically unmarshal any type T +type Loader[O, T any] struct { + Builder[O, T] } -func (b *Loader[T]) UnmarshalJSON(raw []byte) error { +func (b *Loader[O, T]) UnmarshalJSON(raw []byte) error { typ := new(T) typStr := reflect.TypeOf(typ).String() typReg, err := loadTypeReg(typStr) if err != nil { return err } - registryForType := typReg.(*Registry[T]) + registryForType := typReg.(*Registry[O, T]) loadType := gjson.Get(string(raw), "type") if !loadType.Exists() { @@ -110,8 +112,12 @@ func (b *Loader[T]) UnmarshalJSON(raw []byte) error { return json.Unmarshal(raw, b.Builder) } -func (l Loader[T]) Configure() (T, error) { - return l.Builder.Configure() +func (l Loader[O, T]) Configure(opts ...func(O)) (T, error) { + var t T + if l.Builder == nil { + return t, errors.New("no type registered for configuration") + } + return l.Builder.Configure(opts...) } func replaceEnv(v reflect.Value) { From c6613811a27f1e64b1647cc7f55e18d4865c2ae0 Mon Sep 17 00:00:00 2001 From: Alan Braithwaite Date: Sun, 5 Jan 2025 16:24:07 -0800 Subject: [PATCH 2/3] revert --- loader/loader.go | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/loader/loader.go b/loader/loader.go index c0e5635..f1f08f6 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -33,17 +33,17 @@ func LoadConfig(bts []byte, cfg any) error { return nil } -type Builder[O, T any] interface { - Configure(...func(O)) (T, error) +type Builder[T any] interface { + Configure(...Option) (T, error) } -type Registry[O, T any] struct { - m map[string]func() Builder[O, T] +type Registry[T any] struct { + m map[string]func() Builder[T] sync.RWMutex } var registry = struct { - // map[typeString]registry[O, T] where T is variadic and typeString is: + // map[typeString]registry[T] where T is variadic and typeString is: // reflect.TypeOf(T).String() m map[string]any sync.RWMutex @@ -64,7 +64,7 @@ func loadTypeReg(typ string) (any, error) { // Register registers a factory method for a type T with the given type name. T // is typically an interface that is implmented by the struct of type given by // the name. -func Register[O, T any](name string, factory func() Builder[O, T]) { +func Register[T any](name string, factory func() Builder[T]) { registry.Lock() defer registry.Unlock() @@ -74,28 +74,28 @@ func Register[O, T any](name string, factory func() Builder[O, T]) { typStr := reflect.TypeOf(typ).String() typReg, ok := registry.m[typStr] if !ok { - typReg = &Registry[O, T]{ - m: make(map[string]func() Builder[O, T]), + typReg = &Registry[T]{ + m: make(map[string]func() Builder[T]), } registry.m[typStr] = typReg } - registryForType := typReg.(*Registry[O, T]) + registryForType := typReg.(*Registry[T]) registryForType.m[name] = factory } // Loader is a struct which can dyanmically unmarshal any type T -type Loader[O, T any] struct { - Builder[O, T] +type Loader[T any] struct { + Builder[T] } -func (b *Loader[O, T]) UnmarshalJSON(raw []byte) error { +func (b *Loader[T]) UnmarshalJSON(raw []byte) error { typ := new(T) typStr := reflect.TypeOf(typ).String() typReg, err := loadTypeReg(typStr) if err != nil { return err } - registryForType := typReg.(*Registry[O, T]) + registryForType := typReg.(*Registry[T]) loadType := gjson.Get(string(raw), "type") if !loadType.Exists() { @@ -112,7 +112,11 @@ func (b *Loader[O, T]) UnmarshalJSON(raw []byte) error { return json.Unmarshal(raw, b.Builder) } -func (l Loader[O, T]) Configure(opts ...func(O)) (T, error) { +type Option interface { + Apply() +} + +func (l Loader[T]) Configure(opts ...Option) (T, error) { var t T if l.Builder == nil { return t, errors.New("no type registered for configuration") From dd8c82620c0f604559b0b1465a9741c6f2d708f4 Mon Sep 17 00:00:00 2001 From: Alan Braithwaite Date: Sun, 5 Jan 2025 16:26:14 -0800 Subject: [PATCH 3/3] remove opts --- loader/loader.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/loader/loader.go b/loader/loader.go index f1f08f6..5f32b04 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -34,7 +34,7 @@ func LoadConfig(bts []byte, cfg any) error { } type Builder[T any] interface { - Configure(...Option) (T, error) + Configure() (T, error) } type Registry[T any] struct { @@ -112,16 +112,12 @@ func (b *Loader[T]) UnmarshalJSON(raw []byte) error { return json.Unmarshal(raw, b.Builder) } -type Option interface { - Apply() -} - -func (l Loader[T]) Configure(opts ...Option) (T, error) { +func (l Loader[T]) Configure() (T, error) { var t T if l.Builder == nil { return t, errors.New("no type registered for configuration") } - return l.Builder.Configure(opts...) + return l.Builder.Configure() } func replaceEnv(v reflect.Value) {