github.com/goki/ki@v1.1.11/kit/ptrs.go (about) 1 // Copyright (c) 2018, The GoKi Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package kit 6 7 import ( 8 "reflect" 9 ) 10 11 // These are a set of consistently-named functions for navigating pointer 12 // types and values within the reflect system 13 14 ///////////////////////////////////////////////// 15 // reflect.Type versions 16 17 // NonPtrType returns the non-pointer underlying type 18 func NonPtrType(typ reflect.Type) reflect.Type { 19 if typ == nil { 20 return typ 21 } 22 for typ.Kind() == reflect.Ptr { 23 typ = typ.Elem() 24 } 25 return typ 26 } 27 28 // PtrType returns the pointer type for given type, if given type is not already a Ptr 29 func PtrType(typ reflect.Type) reflect.Type { 30 if typ == nil { 31 return typ 32 } 33 if typ.Kind() != reflect.Ptr { 34 typ = reflect.PtrTo(typ) 35 } 36 return typ 37 } 38 39 // OnePtrType returns a type that is exactly one pointer away from a non-pointer type 40 func OnePtrType(typ reflect.Type) reflect.Type { 41 if typ == nil { 42 return typ 43 } 44 if typ.Kind() != reflect.Ptr { 45 typ = reflect.PtrTo(typ) 46 } else { 47 for typ.Elem().Kind() == reflect.Ptr { 48 typ = typ.Elem() 49 } 50 } 51 return typ 52 } 53 54 ///////////////////////////////////////////////// 55 // reflect.Value versions 56 57 // NonPtrValue returns the non-pointer underlying value 58 func NonPtrValue(v reflect.Value) reflect.Value { 59 for v.Kind() == reflect.Ptr { 60 v = v.Elem() 61 } 62 return v 63 } 64 65 // PtrValue returns the pointer version (Addr()) of the underlying value if 66 // the value is not already a Ptr 67 func PtrValue(v reflect.Value) reflect.Value { 68 if v.CanAddr() && v.Kind() != reflect.Ptr { 69 v = v.Addr() 70 } 71 return v 72 } 73 74 // OnePtrValue returns a value that is exactly one pointer away 75 // from a non-pointer type 76 func OnePtrValue(v reflect.Value) reflect.Value { 77 if v.Kind() != reflect.Ptr { 78 if v.CanAddr() { 79 v = v.Addr() 80 } 81 } else { 82 for v.Elem().Kind() == reflect.Ptr { 83 v = v.Elem() 84 } 85 } 86 return v 87 } 88 89 // OnePtrUnderlyingValue returns a value that is exactly one pointer away 90 // from a non-pointer type, and also goes through an interface to find the 91 // actual underlying type behind the interface. 92 func OnePtrUnderlyingValue(v reflect.Value) reflect.Value { 93 opv := OnePtrValue(v) 94 npv := NonPtrValue(opv) 95 itv := reflect.ValueOf(npv.Interface()) 96 if itv.Kind() == reflect.Ptr { 97 // for this to still be a ptr, means that orig Value is 98 // an interface, so this is the underlying value of that interface 99 opv = OnePtrValue(itv) 100 } 101 return opv 102 } 103 104 // MakePtrValue makes a new pointer to the given value, adding an extra level 105 // of indirection, and then removing that indirection, resulting in something 106 // that is now addressable / assignable -- this is necessary for enums.. 107 func MakePtrValue(v reflect.Value) reflect.Value { 108 np := reflect.New(PtrType(v.Type())) 109 pi := np.Interface() 110 pi = v.Interface() // assign pointer using interface assignment instead of set.. 111 p := reflect.ValueOf(pi) // has a double pointer, remove that last one 112 return p.Elem() 113 } 114 115 // UnhideIfaceValue returns a reflect.Value for any of the Make* functions 116 // that is actually assignable -- even though these functions return a pointer 117 // to the new object, it is somehow hidden behind an interface{} and this 118 // magic code, posted by someone somewhere that I cannot now find again, 119 // un-hides it.. 120 func UnhideIfaceValue(v reflect.Value) reflect.Value { 121 vn := reflect.ValueOf(v.Interface()) 122 typ := vn.Type() 123 ptr := reflect.New(typ) 124 ptr.Elem().Set(vn) 125 return ptr 126 } 127 128 ///////////////////////////////////////////////// 129 // interface{} versions 130 131 // NonPtrInterface returns the non-pointer value of an interface 132 func NonPtrInterface(el interface{}) interface{} { 133 v := reflect.ValueOf(el) 134 for v.Kind() == reflect.Ptr { 135 v = v.Elem() 136 } 137 return v.Interface() 138 } 139 140 // PtrInterface returns the pointer value of an interface, if it is possible to get one through Addr() 141 func PtrInterface(el interface{}) interface{} { 142 v := reflect.ValueOf(el) 143 if v.Kind() == reflect.Ptr { 144 return el 145 } 146 if v.CanAddr() { 147 return v.Addr().Interface() 148 } 149 return el 150 } 151 152 // OnePtrInterface returns the pointer value of an interface, if it is possible to get one through Addr() 153 func OnePtrInterface(el interface{}) interface{} { 154 return OnePtrValue(reflect.ValueOf(el)).Interface() 155 }