wm/src/bsp/cfg/cfg.go

174 lines
3.5 KiB
Go
Raw Normal View History

2023-06-11 14:11:36 +00:00
package cfg
import (
"fmt"
"reflect"
"strconv"
"strings"
"tuxpa.in/t/wm/src/copies"
)
// Read will return the first non nil value or the default value
func Read[T any](xs ...*T) T {
for _, v := range xs {
if v != nil {
return *v
}
}
// zero value if all else fails
return *new(T)
}
func ReadFunc[T any, V any](fn func(*T) *V, xs ...*T) V {
for _, v := range xs {
if v == nil {
continue
}
vv := fn(v)
if vv != nil {
return *vv
}
}
return *new(V)
}
type Modifier[T any] struct {
Ref T
setters map[string]func(v string) error
getters map[string]func() (string, error)
}
func NewModifier[T any](start T) *Modifier[T] {
m := &Modifier[T]{
Ref: start,
setters: map[string]func(v string) error{},
getters: map[string]func() (string, error){},
}
m.setup()
return m
}
func (m *Modifier[T]) Set(k, v string) error {
fn, ok := m.setters[k]
if !ok {
// TODO: some error here
return nil
}
return fn(v)
}
func (m *Modifier[T]) GetString(k string) (string, error) {
fn, ok := m.getters[k]
if !ok {
// TODO: some error here
return "", fmt.Errorf("config key '%s' not found", k)
}
return fn()
}
func (m *Modifier[T]) FillDefaults() {
rt := reflect.TypeOf(m.Ref).Elem()
for i := 0; i < rt.NumField(); i++ {
ft := rt.Field(i)
k := ft.Tag.Get("cfg")
dv := ft.Tag.Get("default")
if dv == "" {
continue
}
m.Set(k, dv)
}
return
}
func (m *Modifier[T]) setup() {
// grab the value
rv := reflect.ValueOf(m.Ref).Elem()
rt := reflect.TypeOf(m.Ref).Elem()
for i := 0; i < rv.NumField(); i++ {
fv := rv.Field(i)
ft := rt.Field(i)
k := ft.Tag.Get("cfg")
kind := ft.Type.Elem().Kind()
switch kind {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
m.setters[k] = func(v string) error {
val, err := strconv.ParseUint(v, 10, 64)
if err != nil {
return copies.NewInvalidValueErr(k, v)
}
if fv.IsNil() {
fv.Set(reflect.New(ft.Type.Elem()))
}
fv.Elem().SetUint(uint64(val))
return nil
}
m.getters[k] = func() (string, error) {
if fv.IsNil() {
return "", nil
}
return fmt.Sprintf("%v", fv.Elem()), nil
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
m.setters[k] = func(v string) error {
val, err := strconv.Atoi(v)
if err != nil {
return copies.NewInvalidValueErr(k, v)
}
if fv.IsNil() {
fv.Set(reflect.New(ft.Type.Elem()))
}
fv.Elem().SetInt(int64(val))
return nil
}
m.getters[k] = func() (string, error) {
if fv.IsNil() {
return "", nil
}
return fmt.Sprintf("%v", fv.Elem()), nil
}
case reflect.Bool:
m.setters[k] = func(v string) error {
var b bool
switch strings.ToLower(v) {
case "true", "on":
b = true
case "false", "off":
b = false
default:
return copies.NewInvalidValueErr(k, v)
}
if fv.IsNil() {
fv.Set(reflect.New(ft.Type.Elem()))
}
fv.Elem().SetBool(b)
return nil
}
m.getters[k] = func() (string, error) {
if fv.IsNil() {
return "", nil
}
return fmt.Sprintf("%v", fv.Elem()), nil
}
case reflect.String:
m.setters[k] = func(v string) error {
if fv.IsNil() {
fv.Set(reflect.New(ft.Type.Elem()))
}
fv.Elem().SetString(strings.TrimSpace(v))
return nil
}
m.getters[k] = func() (string, error) {
if fv.IsNil() {
return "", nil
}
return fmt.Sprintf("%v", fv.Elem()), nil
}
}
}
}
func getStructTag(f reflect.StructField, tagName string) string {
return string(f.Tag.Get(tagName))
}