convert.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. // ⚡️ Fiber is an Express inspired web framework written in Go with ☕️
  2. // 🤖 Github Repository: https://github.com/gofiber/fiber
  3. // 📌 API Documentation: https://docs.gofiber.io
  4. package utils
  5. import (
  6. "fmt"
  7. "math"
  8. "reflect"
  9. "strconv"
  10. "strings"
  11. "time"
  12. "github.com/gofiber/utils/v2/internal/unsafeconv"
  13. )
  14. // UnsafeString returns a string pointer without allocation
  15. func UnsafeString(b []byte) string {
  16. return unsafeconv.UnsafeString(b)
  17. }
  18. // UnsafeBytes returns a byte pointer without allocation.
  19. func UnsafeBytes(s string) []byte {
  20. return unsafeconv.UnsafeBytes(s)
  21. }
  22. // CopyString copies a string to make it immutable
  23. func CopyString(s string) string {
  24. // #nosec G103
  25. return string(UnsafeBytes(s))
  26. }
  27. // #nosec G103
  28. // CopyBytes copies a slice to make it immutable
  29. func CopyBytes(b []byte) []byte {
  30. tmp := make([]byte, len(b))
  31. copy(tmp, b)
  32. return tmp
  33. }
  34. const (
  35. uByte = 1 << (10 * iota)
  36. uKilobyte
  37. uMegabyte
  38. uGigabyte
  39. uTerabyte
  40. uPetabyte
  41. uExabyte
  42. )
  43. // ByteSize returns a human-readable byte string of the form 10M, 12.5K, and so forth.
  44. // The unit that results in the smallest number greater than or equal to 1 is always chosen.
  45. // Maximum supported input is math.MaxUint64 / 10 (≈ 1844674407370955161).
  46. func ByteSize(bytes uint64) string {
  47. const maxSafe = math.MaxUint64 / 10
  48. unit := ""
  49. div := uint64(1)
  50. switch {
  51. case bytes >= uExabyte:
  52. unit = "EB"
  53. div = uExabyte
  54. case bytes >= uPetabyte:
  55. unit = "PB"
  56. div = uPetabyte
  57. case bytes >= uTerabyte:
  58. unit = "TB"
  59. div = uTerabyte
  60. case bytes >= uGigabyte:
  61. unit = "GB"
  62. div = uGigabyte
  63. case bytes >= uMegabyte:
  64. unit = "MB"
  65. div = uMegabyte
  66. case bytes >= uKilobyte:
  67. unit = "KB"
  68. div = uKilobyte
  69. case bytes >= uByte:
  70. unit = "B"
  71. default:
  72. return "0B"
  73. }
  74. buf := make([]byte, 0, 16)
  75. if div == 1 {
  76. buf = AppendUint(buf, bytes)
  77. buf = append(buf, unit...)
  78. return UnsafeString(buf)
  79. }
  80. // Fix: cap bytes to maxSafe for overflow, but format as fractional
  81. if bytes > maxSafe {
  82. bytes = maxSafe
  83. }
  84. scaled := (bytes/div)*10 + ((bytes%div)*10+div/2)/div
  85. integer := scaled / 10
  86. fractional := scaled % 10
  87. buf = AppendUint(buf, integer)
  88. if fractional > 0 {
  89. buf = append(buf, '.')
  90. buf = AppendUint(buf, fractional)
  91. }
  92. buf = append(buf, unit...)
  93. return UnsafeString(buf)
  94. }
  95. // ToString Change arg to string
  96. func ToString(arg any, timeFormat ...string) string {
  97. switch v := arg.(type) {
  98. case int:
  99. return FormatInt(int64(v))
  100. case int8:
  101. return FormatInt8(v)
  102. case int16:
  103. return FormatInt16(v)
  104. case int32:
  105. return FormatInt32(v)
  106. case int64:
  107. return FormatInt(v)
  108. case uint:
  109. return FormatUint(uint64(v))
  110. case uint8:
  111. return FormatUint8(v)
  112. case uint16:
  113. return FormatUint16(v)
  114. case uint32:
  115. return FormatUint32(v)
  116. case uint64:
  117. return FormatUint(v)
  118. case string:
  119. return v
  120. case []byte:
  121. return string(v)
  122. case bool:
  123. return strconv.FormatBool(v)
  124. case float32:
  125. return strconv.FormatFloat(float64(v), 'f', -1, 32)
  126. case float64:
  127. return strconv.FormatFloat(v, 'f', -1, 64)
  128. case time.Time:
  129. if len(timeFormat) > 0 {
  130. return v.Format(timeFormat[0])
  131. }
  132. return v.Format("2006-01-02 15:04:05")
  133. case reflect.Value:
  134. return ToString(v.Interface(), timeFormat...)
  135. case fmt.Stringer:
  136. return v.String()
  137. // Handle common pointer types directly to avoid reflection
  138. case *string:
  139. if v != nil {
  140. return *v
  141. }
  142. return ""
  143. case *int:
  144. if v != nil {
  145. return FormatInt(int64(*v))
  146. }
  147. return "0"
  148. case *int64:
  149. if v != nil {
  150. return FormatInt(*v)
  151. }
  152. return "0"
  153. case *uint64:
  154. if v != nil {
  155. return FormatUint(*v)
  156. }
  157. return "0"
  158. case *float64:
  159. if v != nil {
  160. return strconv.FormatFloat(*v, 'f', -1, 64)
  161. }
  162. return "0"
  163. case *bool:
  164. if v != nil {
  165. return strconv.FormatBool(*v)
  166. }
  167. return "false"
  168. // Handle common slice types directly to avoid reflection
  169. case []string:
  170. if len(v) == 0 {
  171. return "[]"
  172. }
  173. var buf strings.Builder
  174. buf.Grow(len(v) * 8) // Pre-allocate approximate size
  175. buf.WriteByte('[')
  176. for i, s := range v {
  177. if i > 0 {
  178. buf.WriteByte(' ')
  179. }
  180. buf.WriteString(s)
  181. }
  182. buf.WriteByte(']')
  183. return buf.String()
  184. case []int:
  185. if len(v) == 0 {
  186. return "[]"
  187. }
  188. var buf strings.Builder
  189. buf.Grow(len(v) * 4) // Pre-allocate approximate size
  190. buf.WriteByte('[')
  191. for i, n := range v {
  192. if i > 0 {
  193. buf.WriteByte(' ')
  194. }
  195. buf.WriteString(FormatInt(int64(n)))
  196. }
  197. buf.WriteByte(']')
  198. return buf.String()
  199. default:
  200. // Check if the type is a pointer by using reflection
  201. rv := reflect.ValueOf(arg)
  202. kind := rv.Kind()
  203. if kind == reflect.Ptr && !rv.IsNil() {
  204. // Dereference the pointer and recursively call ToString
  205. return ToString(rv.Elem().Interface(), timeFormat...)
  206. } else if kind == reflect.Slice || kind == reflect.Array {
  207. // handle slices
  208. n := rv.Len()
  209. if n == 0 {
  210. return "[]"
  211. }
  212. var buf strings.Builder
  213. buf.Grow(n * 8) // Pre-allocate approximate size
  214. buf.WriteByte('[')
  215. for i := range n {
  216. if i > 0 {
  217. buf.WriteByte(' ')
  218. }
  219. buf.WriteString(ToString(rv.Index(i).Interface()))
  220. }
  221. buf.WriteByte(']')
  222. return buf.String()
  223. }
  224. // For types not explicitly handled, use fmt.Sprint to generate a string representation
  225. return fmt.Sprint(arg)
  226. }
  227. }