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  }