package serde import ( "reflect" ) // Indirect will walk a value's interface or pointer value types. Returning // the final value or the value a unmarshaler is defined on. // // Based on the enoding/json type reflect value type indirection in Go Stdlib // https://golang.org/src/encoding/json/decode.go Indirect func. func Indirect(v reflect.Value, decodingNull bool) reflect.Value { v0 := v haveAddr := false if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { v = v.Addr() haveAddr = true } for { if v.Kind() == reflect.Interface && !v.IsNil() { e := v.Elem() if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { haveAddr = false v = e continue } } if v.Kind() != reflect.Ptr { break } if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() { break } if v.IsNil() { v.Set(reflect.New(v.Type().Elem())) } if haveAddr { v = v0 haveAddr = false } else { v = v.Elem() } } return v } // PtrToValue given the input value will dereference pointers and returning the element pointed to. func PtrToValue(in interface{}) interface{} { v := reflect.ValueOf(in) if v.Kind() == reflect.Ptr { v = v.Elem() } if !v.IsValid() { return nil } if v.Kind() == reflect.Ptr { return PtrToValue(v.Interface()) } return v.Interface() } // IsZeroValue returns whether v is the zero-value for its type. func IsZeroValue(v reflect.Value) bool { switch v.Kind() { case reflect.Invalid: return true case reflect.Array: return v.Len() == 0 case reflect.Map, reflect.Slice: return v.IsNil() case reflect.String: return v.Len() == 0 case reflect.Bool: return !v.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.Interface, reflect.Ptr: return v.IsNil() } return false } // ValueElem walks interface and pointer types and returns the underlying element. func ValueElem(v reflect.Value) reflect.Value { switch v.Kind() { case reflect.Interface, reflect.Ptr: for v.Kind() == reflect.Interface || v.Kind() == reflect.Ptr { v = v.Elem() } } return v }