Skip to content
Snippets Groups Projects
Select Git revision
  • 7424b9aca56ec5f4d818b1bed9861856ecd9d859
  • master default protected
  • v1.16.5
  • v1.16.4
  • v1.16.3
  • v1.16.2
  • v1.16.1
  • v1.16.0
  • v1.15.0
  • v1.14.0
  • v1.13.2
  • v1.13.1
  • v1.13.0
  • v1.12.0
  • v1.11.0
  • v1.10.2
  • v1.10.1
  • v1.10.0
  • v1.9.0
  • v1.8.3
  • v1.8.2
  • v1.8.1
22 results

pathfind.go

  • 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
    
    }