goki.dev/laser@v0.1.34/ptrs.go (about) 1 // Copyright (c) 2023, 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 laser 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.Kind() != reflect.Ptr { 69 if v.CanAddr() { 70 return v.Addr() 71 } 72 pv := reflect.New(v.Type()) 73 pv.Elem().Set(v) 74 return pv 75 } 76 return v 77 } 78 79 // OnePtrValue returns a value that is exactly one pointer away 80 // from a non-pointer type 81 func OnePtrValue(v reflect.Value) reflect.Value { 82 if v.Kind() != reflect.Ptr { 83 if v.CanAddr() { 84 return v.Addr() 85 } 86 pv := reflect.New(v.Type()) 87 pv.Elem().Set(v) 88 return pv 89 } else { 90 for v.Elem().Kind() == reflect.Ptr { 91 v = v.Elem() 92 } 93 } 94 return v 95 } 96 97 // OnePtrUnderlyingValue returns a value that is exactly one pointer away 98 // from a non-pointer type, and also goes through an interface to find the 99 // actual underlying type behind the interface. 100 func OnePtrUnderlyingValue(v reflect.Value) reflect.Value { 101 npv := NonPtrValue(v) 102 if ValueIsZero(npv) { 103 return npv 104 } 105 for npv.Type().Kind() == reflect.Interface || npv.Type().Kind() == reflect.Pointer { 106 npv = npv.Elem() 107 } 108 return OnePtrValue(npv) 109 } 110 111 // UnhideAnyValue returns a reflect.Value for any of the Make* functions 112 // that is actually assignable -- even though these functions return a pointer 113 // to the new object, it is somehow hidden behind an interface{} and this 114 // magic code, posted by someone somewhere that I cannot now find again, 115 // un-hides it.. 116 func UnhideAnyValue(v reflect.Value) reflect.Value { 117 vn := reflect.ValueOf(v.Interface()) 118 typ := vn.Type() 119 ptr := reflect.New(typ) 120 ptr.Elem().Set(vn) 121 return ptr 122 } 123 124 ///////////////////////////////////////////////// 125 // interface{} versions 126 127 // NonPtrInterface returns the non-pointer value of an interface 128 func NonPtrInterface(el any) any { 129 v := reflect.ValueOf(el) 130 for v.Kind() == reflect.Ptr { 131 v = v.Elem() 132 } 133 return v.Interface() 134 } 135 136 // PtrInterface returns the pointer value of an interface, if it is possible to get one through Addr() 137 func PtrInterface(el any) any { 138 v := reflect.ValueOf(el) 139 if v.Kind() == reflect.Ptr { 140 return el 141 } 142 if v.CanAddr() { 143 return v.Addr().Interface() 144 } 145 return el 146 } 147 148 // OnePtrInterface returns the pointer value of an interface, if it is possible to get one through Addr() 149 func OnePtrInterface(el any) any { 150 return OnePtrValue(reflect.ValueOf(el)).Interface() 151 }