github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/easy/utils.go (about) 1 package easy 2 3 import ( 4 "reflect" 5 "runtime" 6 "strings" 7 8 "github.com/jxskiss/gopkg/v2/unsafe/reflectx" 9 ) 10 11 // SetDefault checks whether dst points to a zero value, if yes, it sets 12 // the first non-zero value to dst. 13 // dst must be a pointer to same type as value, else it panics. 14 func SetDefault(dst any, value ...any) { 15 dstVal := reflect.ValueOf(dst) 16 if dstVal.Kind() != reflect.Ptr || !reflect.Indirect(dstVal).IsValid() { 17 panic("SetDefault: dst must be a non-nil pointer") 18 } 19 if reflect.Indirect(dstVal).IsZero() { 20 kind := dstVal.Elem().Kind() 21 for _, x := range value { 22 xval := reflect.ValueOf(x) 23 if !xval.IsZero() { 24 switch kind { 25 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 26 dstVal.Elem().SetInt(reflectx.ReflectInt(xval)) 27 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 28 dstVal.Elem().SetUint(uint64(reflectx.ReflectInt(xval))) 29 case reflect.Float32, reflect.Float64: 30 dstVal.Elem().SetFloat(xval.Float()) 31 default: 32 dstVal.Elem().Set(xval) 33 } 34 break 35 } 36 } 37 } 38 } 39 40 // Caller returns function name, filename, and the line number of the caller. 41 // The argument skip is the number of stack frames to ascend, with 0 42 // identifying the caller of Caller. 43 func Caller(skip int) (name, file string, line int) { 44 pc, file, line, _ := runtime.Caller(skip + 1) 45 name = runtime.FuncForPC(pc).Name() 46 for i := len(name) - 1; i >= 0; i-- { 47 if name[i] == '/' { 48 name = name[i+1:] 49 break 50 } 51 } 52 pathSepCnt := 0 53 for i := len(file) - 1; i >= 0; i-- { 54 if file[i] == '/' { 55 pathSepCnt++ 56 if pathSepCnt == 2 { 57 file = file[i+1:] 58 break 59 } 60 } 61 } 62 return 63 } 64 65 // CallerName returns the function name of the direct caller. 66 // This is a convenient wrapper around Caller. 67 func CallerName() string { 68 name, _, _ := Caller(1) 69 return name 70 } 71 72 // SingleJoin joins the given text segments using sep. 73 // No matter whether a segment begins or ends with sep or not, it 74 // guarantees that only one sep appears between two segments. 75 func SingleJoin(sep string, text ...string) string { 76 if len(text) == 0 { 77 return "" 78 } 79 result := text[0] 80 for _, next := range text[1:] { 81 asep := strings.HasSuffix(result, sep) 82 bsep := strings.HasPrefix(next, sep) 83 switch { 84 case asep && bsep: 85 result += next[len(sep):] 86 case !asep && !bsep: 87 result += sep + next 88 default: 89 result += next 90 } 91 } 92 return result 93 } 94 95 // SlashJoin joins the given path segments using "/". 96 // No matter whether a segment begins or ends with "/" or not, it guarantees 97 // that only one "/" appears between two segments. 98 func SlashJoin(path ...string) string { 99 return SingleJoin("/", path...) 100 }