174 lines
3.5 KiB
Go
174 lines
3.5 KiB
Go
|
|
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))
|
||
|
|
}
|