goki.dev/laser@v0.1.34/types.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  	"path"
     9  	"reflect"
    10  
    11  	"goki.dev/glop/sentence"
    12  )
    13  
    14  // LongTypeName returns the long, full package-path qualified type name.
    15  // This is guaranteed to be unique and used for internal storage of
    16  // several maps to avoid any conflicts.  It is also very quick to compute.
    17  func LongTypeName(typ reflect.Type) string {
    18  	nptyp := NonPtrType(typ)
    19  	nm := nptyp.Name()
    20  	if nm != "" {
    21  		return nptyp.PkgPath() + "." + nm
    22  	}
    23  	return typ.String()
    24  }
    25  
    26  // ShortTypeName returns the short version of a package-qualified type name
    27  // which just has the last element of the path.  This is what is used in
    28  // standard Go programming, and is is used for the key to lookup reflect.Type
    29  // names -- i.e., this is what you should save in a JSON file.
    30  // The potential naming conflict is worth the brevity, and typically a given
    31  // file will only contain mutually-compatible, non-conflicting types.
    32  // This is cached in ShortNames because the path.Base computation is apparently
    33  // a bit slow.
    34  func ShortTypeName(typ reflect.Type) string {
    35  	nptyp := NonPtrType(typ)
    36  	nm := nptyp.Name()
    37  	if nm != "" {
    38  		return path.Base(nptyp.PkgPath()) + "." + nm
    39  	}
    40  	return typ.String()
    41  }
    42  
    43  // FriendlyTypeName returns a user-friendly version of the name of the given type.
    44  // It transforms it into sentence case, excludes the package, and converts various
    45  // builtin types into more friendly forms (eg: "int" to "Number").
    46  func FriendlyTypeName(typ reflect.Type) string {
    47  	nptyp := NonPtrType(typ)
    48  	nm := nptyp.Name()
    49  
    50  	// if it is named, we use that
    51  	if nm != "" {
    52  		switch nm {
    53  		case "string":
    54  			return "Text"
    55  		case "float32", "float64", "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr":
    56  			return "Number"
    57  		}
    58  		return sentence.Case(nm)
    59  	}
    60  
    61  	// otherwise, we fall back on Kind
    62  	switch nptyp.Kind() {
    63  	case reflect.Slice, reflect.Array, reflect.Map:
    64  		return FriendlyTypeName(nptyp.Elem()) + "s"
    65  	case reflect.Func:
    66  		str := "Function of"
    67  		ni := nptyp.NumIn()
    68  		for i := 0; i < ni; i++ {
    69  			str += FriendlyTypeName(nptyp.In(i))
    70  			if ni == 2 && i == 0 {
    71  				str += " and "
    72  			} else if i == ni-2 {
    73  				str += ", and "
    74  			} else if i < ni-1 {
    75  				str += ", "
    76  			}
    77  		}
    78  		return str
    79  	}
    80  	if nptyp.String() == "interface {}" {
    81  		return "Value"
    82  	}
    83  	return nptyp.String()
    84  }
    85  
    86  // TypeFor returns the [reflect.Type] that represents the type argument T.
    87  // It is a copy of [reflect.TypeFor], which will likely be added in Go 1.22
    88  // (see https://github.com/golang/go/issues/60088)
    89  func TypeFor[T any]() reflect.Type {
    90  	return reflect.TypeOf((*T)(nil)).Elem()
    91  }
    92  
    93  // CloneToType creates a new object of given type, and uses SetRobust to copy
    94  // an existing value (of perhaps another type) into it
    95  func CloneToType(typ reflect.Type, val any) reflect.Value {
    96  	vn := reflect.New(typ)
    97  	evi := vn.Interface()
    98  	SetRobust(evi, val)
    99  	return vn
   100  }
   101  
   102  // MakeOfType creates a new object of given type with appropriate magic foo to
   103  // make it usable
   104  func MakeOfType(typ reflect.Type) reflect.Value {
   105  	if NonPtrType(typ).Kind() == reflect.Map {
   106  		return MakeMap(typ)
   107  	} else if NonPtrType(typ).Kind() == reflect.Slice {
   108  		return MakeSlice(typ, 0, 0)
   109  	}
   110  	vn := reflect.New(typ)
   111  	return vn
   112  }