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  }