github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekastr/to_s.go (about) 1 // Copyright © 2020. All rights reserved. 2 // Author: Ilya Stroy. 3 // Contacts: iyuryevich@pm.me, https://github.com/qioalice 4 // License: https://opensource.org/licenses/MIT 5 6 package ekastr 7 8 import ( 9 "fmt" 10 "reflect" 11 "strconv" 12 "unsafe" 13 14 "github.com/qioalice/ekago/v3/internal/ekaclike" 15 16 "github.com/modern-go/reflect2" 17 ) 18 19 //goland:noinspection GoSnakeCaseUsage 20 const ( 21 TO_S_HANDLE_ARRAYS uint8 = 0x01 22 TO_S_HANDLE_STRUCTS uint8 = 0x02 23 TO_S_HANDLE_MAPS uint8 = 0x04 24 TO_S_DEREFERENCE_PTR uint8 = 0x08 25 ) 26 27 /* 28 ToString is a special type that allows you to get a string representation 29 of any type's passed argument. It returns an empty string for nil interface. 30 */ 31 func ToString(i any) string { 32 iface := ekaclike.UnpackInterface(i) 33 return ToStringUnsafe(iface.Type, iface.Word, 0xFF) 34 } 35 36 /* 37 ToStringUnsafe is the same as ToString but allows you to reject handling 38 arrays, structs, maps, pointers. It also awaits to get unpacked Golang interface 39 as both of rtype's and data's pointers. Zero safe - returns an empty string then. 40 */ 41 func ToStringUnsafe(rtype uintptr, word unsafe.Pointer, mask uint8) string { 42 43 if word == nil && rtype != 0 { 44 switch rtype { 45 case ekaclike.RTypeBool, ekaclike.RTypeString, ekaclike.RTypeBytes: 46 return "" 47 case ekaclike.RTypeInt, 48 ekaclike.RTypeInt8, ekaclike.RTypeInt16, 49 ekaclike.RTypeInt32, ekaclike.RTypeInt64, 50 ekaclike.RTypeUint, 51 ekaclike.RTypeUint8, ekaclike.RTypeUint16, 52 ekaclike.RTypeUint32, ekaclike.RTypeUint64, 53 ekaclike.RTypeFloat32, ekaclike.RTypeFloat64, 54 ekaclike.RTypeComplex64, ekaclike.RTypeComplex128: 55 return "0" 56 } 57 switch reflect2.TypeOf(ekaclike.Interface{Type: rtype}.Pack()).Kind() { 58 case reflect.Array, reflect.Slice: 59 return "[]" 60 case reflect.Struct, reflect.Map: 61 return "{}" 62 default: 63 return "" 64 } 65 } 66 67 switch { 68 69 case rtype == 0: 70 return "" 71 72 case rtype == ekaclike.RTypeString: 73 return *(*string)(word) 74 75 case rtype == ekaclike.RTypeBytes: 76 return B2S(*(*[]byte)(word)) 77 78 case rtype == ekaclike.RTypeBool: 79 if *(*bool)(word) { 80 return "true" 81 } else { 82 return "false" 83 } 84 85 case rtype == ekaclike.RTypeInt: 86 return strconv.FormatInt(int64(*(*int)(word)), 10) 87 case rtype == ekaclike.RTypeInt8: 88 return strconv.FormatInt(int64(*(*int8)(word)), 10) 89 case rtype == ekaclike.RTypeInt16: 90 return strconv.FormatInt(int64(*(*int16)(word)), 10) 91 case rtype == ekaclike.RTypeInt32: 92 return strconv.FormatInt(int64(*(*int32)(word)), 10) 93 case rtype == ekaclike.RTypeInt64: 94 return strconv.FormatInt(*(*int64)(word), 10) 95 96 case rtype == ekaclike.RTypeUint: 97 return strconv.FormatUint(uint64(*(*uint)(word)), 10) 98 case rtype == ekaclike.RTypeUint8: 99 return strconv.FormatUint(uint64(*(*uint8)(word)), 10) 100 case rtype == ekaclike.RTypeUint16: 101 return strconv.FormatUint(uint64(*(*uint16)(word)), 10) 102 case rtype == ekaclike.RTypeUint32: 103 return strconv.FormatUint(uint64(*(*uint32)(word)), 10) 104 case rtype == ekaclike.RTypeUint64: 105 return strconv.FormatUint(*(*uint64)(word), 10) 106 107 case rtype == ekaclike.RTypeFloat32: 108 return strconv.FormatFloat(float64(*(*float32)(word)), 'f', 2, 32) 109 case rtype == ekaclike.RTypeFloat64: 110 return strconv.FormatFloat(*(*float64)(word), 'f', 2, 64) 111 112 case rtype == ekaclike.RTypeComplex64: 113 return strconv.FormatComplex(complex128(*(*complex64)(word)), 'f', 2, 64) 114 case rtype == ekaclike.RTypeComplex128: 115 return strconv.FormatComplex(*(*complex128)(word), 'f', 2, 128) 116 } 117 118 // All standard types are over. 119 // Next types will be complex. 120 121 var ( 122 eface = ekaclike.Interface{Type: rtype, Word: word}.Pack() 123 typ = reflect2.TypeOf(eface) 124 kind = typ.Kind() 125 ) 126 127 switch { 128 case kind == reflect.Array && mask&TO_S_HANDLE_ARRAYS == 0: 129 return "" 130 case kind == reflect.Slice && mask&TO_S_HANDLE_ARRAYS == 0: 131 return "" 132 case kind == reflect.Struct && mask&TO_S_HANDLE_STRUCTS == 0: 133 return "" 134 case kind == reflect.Map && mask&TO_S_HANDLE_MAPS == 0: 135 return "" 136 case kind == reflect.Ptr && mask&TO_S_DEREFERENCE_PTR == 0: 137 return "" 138 } 139 140 // Well, it's complex case and it must be handled. 141 142 // TODO: Support fmt.Stringer interface. 143 // TODO: Separate handle all complex cases more optimised way. 144 return fmt.Sprintf("%+v", eface) 145 }