Something went wrong on our end
Select Git revision
pathfind.go
-
Volker Schukai authoredVolker Schukai authored
pathfind.go 2.25 KiB
package xflags
import (
"reflect"
"strconv"
"strings"
)
// This function returns the value of a field in a struct, given a path to the field.
func getValueFrom[D any](obj D, keyWithDots string) (interface{}, error) {
keySlice := strings.Split(keyWithDots, ".")
v := reflect.ValueOf(obj)
for _, key := range keySlice[0 : len(keySlice)-1] {
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
return nil, newUnsupportedTypePathError(keyWithDots, v.Type())
}
v = v.FieldByName(key)
}
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
// non-supporter type at the top of the path
if v.Kind() != reflect.Struct {
return nil, newUnsupportedTypeAtTopOfPathError(keyWithDots, v.Type())
}
v = v.FieldByName(keySlice[len(keySlice)-1])
if !v.IsValid() {
return nil, newInvalidPathError(keyWithDots)
}
return v.Interface(), nil
}
// This function sets the value of a field in a struct, given a path to the field.
func setValueUsingPath[D any](obj D, keyWithDots string, newValue string) error {
keySlice := strings.Split(keyWithDots, ".")
v := reflect.ValueOf(obj)
for _, key := range keySlice[0 : len(keySlice)-1] {
for v.Kind() != reflect.Ptr {
v = v.Addr()
}
if v.Kind() != reflect.Ptr {
return newUnsupportedTypePathError(keyWithDots, v.Type())
}
elem := v.Elem()
if elem.Kind() != reflect.Struct {
return newUnsupportedTypePathError(keyWithDots, v.Type())
}
v = elem.FieldByName(key)
}
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
// non-supporter type at the top of the path
if v.Kind() != reflect.Struct {
return newUnsupportedTypeAtTopOfPathError(keyWithDots, v.Type())
}
v = v.FieldByName(keySlice[len(keySlice)-1])
if !v.IsValid() {
return newInvalidPathError(keyWithDots)
}
if !v.CanSet() {
return newCannotSetError(keyWithDots)
}
switch v.Kind() {
case reflect.String:
v.SetString(newValue)
case reflect.Int:
s, err := strconv.Atoi(newValue)
if err != nil {
return err
}
v.SetInt(int64(s))
case reflect.Bool:
v.SetBool(newValue == "true")
case reflect.Float64:
s, err := strconv.ParseFloat(newValue, 64)
if err != nil {
return err
}
v.SetFloat(s)
default:
return newUnsupportedTypeAtTopOfPathError(keyWithDots, v.Type())
}
return nil
}