Blame vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value.go

Packit 63bb0d
package awsutil
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"reflect"
Packit 63bb0d
	"regexp"
Packit 63bb0d
	"strconv"
Packit 63bb0d
	"strings"
Packit 63bb0d
Packit 63bb0d
	"github.com/jmespath/go-jmespath"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
var indexRe = regexp.MustCompile(`(.+)\[(-?\d+)?\]$`)
Packit 63bb0d
Packit 63bb0d
// rValuesAtPath returns a slice of values found in value v. The values
Packit 63bb0d
// in v are explored recursively so all nested values are collected.
Packit 63bb0d
func rValuesAtPath(v interface{}, path string, createPath, caseSensitive, nilTerm bool) []reflect.Value {
Packit 63bb0d
	pathparts := strings.Split(path, "||")
Packit 63bb0d
	if len(pathparts) > 1 {
Packit 63bb0d
		for _, pathpart := range pathparts {
Packit 63bb0d
			vals := rValuesAtPath(v, pathpart, createPath, caseSensitive, nilTerm)
Packit 63bb0d
			if len(vals) > 0 {
Packit 63bb0d
				return vals
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
		return nil
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	values := []reflect.Value{reflect.Indirect(reflect.ValueOf(v))}
Packit 63bb0d
	components := strings.Split(path, ".")
Packit 63bb0d
	for len(values) > 0 && len(components) > 0 {
Packit 63bb0d
		var index *int64
Packit 63bb0d
		var indexStar bool
Packit 63bb0d
		c := strings.TrimSpace(components[0])
Packit 63bb0d
		if c == "" { // no actual component, illegal syntax
Packit 63bb0d
			return nil
Packit 63bb0d
		} else if caseSensitive && c != "*" && strings.ToLower(c[0:1]) == c[0:1] {
Packit 63bb0d
			// TODO normalize case for user
Packit 63bb0d
			return nil // don't support unexported fields
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		// parse this component
Packit 63bb0d
		if m := indexRe.FindStringSubmatch(c); m != nil {
Packit 63bb0d
			c = m[1]
Packit 63bb0d
			if m[2] == "" {
Packit 63bb0d
				index = nil
Packit 63bb0d
				indexStar = true
Packit 63bb0d
			} else {
Packit 63bb0d
				i, _ := strconv.ParseInt(m[2], 10, 32)
Packit 63bb0d
				index = &i
Packit 63bb0d
				indexStar = false
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		nextvals := []reflect.Value{}
Packit 63bb0d
		for _, value := range values {
Packit 63bb0d
			// pull component name out of struct member
Packit 63bb0d
			if value.Kind() != reflect.Struct {
Packit 63bb0d
				continue
Packit 63bb0d
			}
Packit 63bb0d
Packit 63bb0d
			if c == "*" { // pull all members
Packit 63bb0d
				for i := 0; i < value.NumField(); i++ {
Packit 63bb0d
					if f := reflect.Indirect(value.Field(i)); f.IsValid() {
Packit 63bb0d
						nextvals = append(nextvals, f)
Packit 63bb0d
					}
Packit 63bb0d
				}
Packit 63bb0d
				continue
Packit 63bb0d
			}
Packit 63bb0d
Packit 63bb0d
			value = value.FieldByNameFunc(func(name string) bool {
Packit 63bb0d
				if c == name {
Packit 63bb0d
					return true
Packit 63bb0d
				} else if !caseSensitive && strings.EqualFold(name, c) {
Packit 63bb0d
					return true
Packit 63bb0d
				}
Packit 63bb0d
				return false
Packit 63bb0d
			})
Packit 63bb0d
Packit 63bb0d
			if nilTerm && value.Kind() == reflect.Ptr && len(components[1:]) == 0 {
Packit 63bb0d
				if !value.IsNil() {
Packit 63bb0d
					value.Set(reflect.Zero(value.Type()))
Packit 63bb0d
				}
Packit 63bb0d
				return []reflect.Value{value}
Packit 63bb0d
			}
Packit 63bb0d
Packit 63bb0d
			if createPath && value.Kind() == reflect.Ptr && value.IsNil() {
Packit 63bb0d
				// TODO if the value is the terminus it should not be created
Packit 63bb0d
				// if the value to be set to its position is nil.
Packit 63bb0d
				value.Set(reflect.New(value.Type().Elem()))
Packit 63bb0d
				value = value.Elem()
Packit 63bb0d
			} else {
Packit 63bb0d
				value = reflect.Indirect(value)
Packit 63bb0d
			}
Packit 63bb0d
Packit 63bb0d
			if value.Kind() == reflect.Slice || value.Kind() == reflect.Map {
Packit 63bb0d
				if !createPath && value.IsNil() {
Packit 63bb0d
					value = reflect.ValueOf(nil)
Packit 63bb0d
				}
Packit 63bb0d
			}
Packit 63bb0d
Packit 63bb0d
			if value.IsValid() {
Packit 63bb0d
				nextvals = append(nextvals, value)
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
		values = nextvals
Packit 63bb0d
Packit 63bb0d
		if indexStar || index != nil {
Packit 63bb0d
			nextvals = []reflect.Value{}
Packit 63bb0d
			for _, valItem := range values {
Packit 63bb0d
				value := reflect.Indirect(valItem)
Packit 63bb0d
				if value.Kind() != reflect.Slice {
Packit 63bb0d
					continue
Packit 63bb0d
				}
Packit 63bb0d
Packit 63bb0d
				if indexStar { // grab all indices
Packit 63bb0d
					for i := 0; i < value.Len(); i++ {
Packit 63bb0d
						idx := reflect.Indirect(value.Index(i))
Packit 63bb0d
						if idx.IsValid() {
Packit 63bb0d
							nextvals = append(nextvals, idx)
Packit 63bb0d
						}
Packit 63bb0d
					}
Packit 63bb0d
					continue
Packit 63bb0d
				}
Packit 63bb0d
Packit 63bb0d
				// pull out index
Packit 63bb0d
				i := int(*index)
Packit 63bb0d
				if i >= value.Len() { // check out of bounds
Packit 63bb0d
					if createPath {
Packit 63bb0d
						// TODO resize slice
Packit 63bb0d
					} else {
Packit 63bb0d
						continue
Packit 63bb0d
					}
Packit 63bb0d
				} else if i < 0 { // support negative indexing
Packit 63bb0d
					i = value.Len() + i
Packit 63bb0d
				}
Packit 63bb0d
				value = reflect.Indirect(value.Index(i))
Packit 63bb0d
Packit 63bb0d
				if value.Kind() == reflect.Slice || value.Kind() == reflect.Map {
Packit 63bb0d
					if !createPath && value.IsNil() {
Packit 63bb0d
						value = reflect.ValueOf(nil)
Packit 63bb0d
					}
Packit 63bb0d
				}
Packit 63bb0d
Packit 63bb0d
				if value.IsValid() {
Packit 63bb0d
					nextvals = append(nextvals, value)
Packit 63bb0d
				}
Packit 63bb0d
			}
Packit 63bb0d
			values = nextvals
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		components = components[1:]
Packit 63bb0d
	}
Packit 63bb0d
	return values
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// ValuesAtPath returns a list of values at the case insensitive lexical
Packit 63bb0d
// path inside of a structure.
Packit 63bb0d
func ValuesAtPath(i interface{}, path string) ([]interface{}, error) {
Packit 63bb0d
	result, err := jmespath.Search(path, i)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return nil, err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	v := reflect.ValueOf(result)
Packit 63bb0d
	if !v.IsValid() || (v.Kind() == reflect.Ptr && v.IsNil()) {
Packit 63bb0d
		return nil, nil
Packit 63bb0d
	}
Packit 63bb0d
	if s, ok := result.([]interface{}); ok {
Packit 63bb0d
		return s, err
Packit 63bb0d
	}
Packit 63bb0d
	if v.Kind() == reflect.Map && v.Len() == 0 {
Packit 63bb0d
		return nil, nil
Packit 63bb0d
	}
Packit 63bb0d
	if v.Kind() == reflect.Slice {
Packit 63bb0d
		out := make([]interface{}, v.Len())
Packit 63bb0d
		for i := 0; i < v.Len(); i++ {
Packit 63bb0d
			out[i] = v.Index(i).Interface()
Packit 63bb0d
		}
Packit 63bb0d
		return out, nil
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return []interface{}{result}, nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// SetValueAtPath sets a value at the case insensitive lexical path inside
Packit 63bb0d
// of a structure.
Packit 63bb0d
func SetValueAtPath(i interface{}, path string, v interface{}) {
Packit 63bb0d
	rvals := rValuesAtPath(i, path, true, false, v == nil)
Packit 63bb0d
	for _, rval := range rvals {
Packit 63bb0d
		if rval.Kind() == reflect.Ptr && rval.IsNil() {
Packit 63bb0d
			continue
Packit 63bb0d
		}
Packit 63bb0d
		setValue(rval, v)
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func setValue(dstVal reflect.Value, src interface{}) {
Packit 63bb0d
	if dstVal.Kind() == reflect.Ptr {
Packit 63bb0d
		dstVal = reflect.Indirect(dstVal)
Packit 63bb0d
	}
Packit 63bb0d
	srcVal := reflect.ValueOf(src)
Packit 63bb0d
Packit 63bb0d
	if !srcVal.IsValid() { // src is literal nil
Packit 63bb0d
		if dstVal.CanAddr() {
Packit 63bb0d
			// Convert to pointer so that pointer's value can be nil'ed
Packit 63bb0d
			//                     dstVal = dstVal.Addr()
Packit 63bb0d
		}
Packit 63bb0d
		dstVal.Set(reflect.Zero(dstVal.Type()))
Packit 63bb0d
Packit 63bb0d
	} else if srcVal.Kind() == reflect.Ptr {
Packit 63bb0d
		if srcVal.IsNil() {
Packit 63bb0d
			srcVal = reflect.Zero(dstVal.Type())
Packit 63bb0d
		} else {
Packit 63bb0d
			srcVal = reflect.ValueOf(src).Elem()
Packit 63bb0d
		}
Packit 63bb0d
		dstVal.Set(srcVal)
Packit 63bb0d
	} else {
Packit 63bb0d
		dstVal.Set(srcVal)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
}