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 }