240 lines
4.7 KiB
Go
240 lines
4.7 KiB
Go
package utils
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"math/big"
|
|
"reflect"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// GenerateID generates a new UUID
|
|
func GenerateID() uuid.UUID {
|
|
return uuid.New()
|
|
}
|
|
|
|
// ParseUUID parses a string to UUID
|
|
func ParseUUID(s string) (uuid.UUID, error) {
|
|
return uuid.Parse(s)
|
|
}
|
|
|
|
// MustParseUUID parses a string to UUID, panics on error
|
|
func MustParseUUID(s string) uuid.UUID {
|
|
id, err := uuid.Parse(s)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return id
|
|
}
|
|
|
|
// IsValidUUID checks if a string is a valid UUID
|
|
func IsValidUUID(s string) bool {
|
|
_, err := uuid.Parse(s)
|
|
return err == nil
|
|
}
|
|
|
|
// ToJSON converts an interface to JSON bytes
|
|
func ToJSON(v interface{}) ([]byte, error) {
|
|
return json.Marshal(v)
|
|
}
|
|
|
|
// FromJSON converts JSON bytes to an interface
|
|
func FromJSON(data []byte, v interface{}) error {
|
|
return json.Unmarshal(data, v)
|
|
}
|
|
|
|
// NowUTC returns the current UTC time
|
|
func NowUTC() time.Time {
|
|
return time.Now().UTC()
|
|
}
|
|
|
|
// TimePtr returns a pointer to the time
|
|
func TimePtr(t time.Time) *time.Time {
|
|
return &t
|
|
}
|
|
|
|
// NowPtr returns a pointer to the current time
|
|
func NowPtr() *time.Time {
|
|
now := NowUTC()
|
|
return &now
|
|
}
|
|
|
|
// BigIntToBytes converts a big.Int to bytes (32 bytes, left-padded)
|
|
func BigIntToBytes(n *big.Int) []byte {
|
|
if n == nil {
|
|
return make([]byte, 32)
|
|
}
|
|
b := n.Bytes()
|
|
if len(b) > 32 {
|
|
return b[:32]
|
|
}
|
|
if len(b) < 32 {
|
|
result := make([]byte, 32)
|
|
copy(result[32-len(b):], b)
|
|
return result
|
|
}
|
|
return b
|
|
}
|
|
|
|
// BytesToBigInt converts bytes to big.Int
|
|
func BytesToBigInt(b []byte) *big.Int {
|
|
return new(big.Int).SetBytes(b)
|
|
}
|
|
|
|
// StringSliceContains checks if a string slice contains a value
|
|
func StringSliceContains(slice []string, value string) bool {
|
|
for _, s := range slice {
|
|
if s == value {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// StringSliceRemove removes a value from a string slice
|
|
func StringSliceRemove(slice []string, value string) []string {
|
|
result := make([]string, 0, len(slice))
|
|
for _, s := range slice {
|
|
if s != value {
|
|
result = append(result, s)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// UniqueStrings returns unique strings from a slice
|
|
func UniqueStrings(slice []string) []string {
|
|
seen := make(map[string]struct{})
|
|
result := make([]string, 0, len(slice))
|
|
for _, s := range slice {
|
|
if _, ok := seen[s]; !ok {
|
|
seen[s] = struct{}{}
|
|
result = append(result, s)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// TruncateString truncates a string to max length
|
|
func TruncateString(s string, maxLen int) string {
|
|
if len(s) <= maxLen {
|
|
return s
|
|
}
|
|
return s[:maxLen]
|
|
}
|
|
|
|
// SafeString returns an empty string if the pointer is nil
|
|
func SafeString(s *string) string {
|
|
if s == nil {
|
|
return ""
|
|
}
|
|
return *s
|
|
}
|
|
|
|
// StringPtr returns a pointer to the string
|
|
func StringPtr(s string) *string {
|
|
return &s
|
|
}
|
|
|
|
// IntPtr returns a pointer to the int
|
|
func IntPtr(i int) *int {
|
|
return &i
|
|
}
|
|
|
|
// BoolPtr returns a pointer to the bool
|
|
func BoolPtr(b bool) *bool {
|
|
return &b
|
|
}
|
|
|
|
// IsZero checks if a value is zero/empty
|
|
func IsZero(v interface{}) bool {
|
|
return reflect.ValueOf(v).IsZero()
|
|
}
|
|
|
|
// Coalesce returns the first non-zero value
|
|
func Coalesce[T comparable](values ...T) T {
|
|
var zero T
|
|
for _, v := range values {
|
|
if v != zero {
|
|
return v
|
|
}
|
|
}
|
|
return zero
|
|
}
|
|
|
|
// MapKeys returns the keys of a map
|
|
func MapKeys[K comparable, V any](m map[K]V) []K {
|
|
keys := make([]K, 0, len(m))
|
|
for k := range m {
|
|
keys = append(keys, k)
|
|
}
|
|
return keys
|
|
}
|
|
|
|
// MapValues returns the values of a map
|
|
func MapValues[K comparable, V any](m map[K]V) []V {
|
|
values := make([]V, 0, len(m))
|
|
for _, v := range m {
|
|
values = append(values, v)
|
|
}
|
|
return values
|
|
}
|
|
|
|
// Min returns the minimum of two values
|
|
func Min[T ~int | ~int64 | ~float64](a, b T) T {
|
|
if a < b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|
|
|
|
// Max returns the maximum of two values
|
|
func Max[T ~int | ~int64 | ~float64](a, b T) T {
|
|
if a > b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|
|
|
|
// Clamp clamps a value between min and max
|
|
func Clamp[T ~int | ~int64 | ~float64](value, min, max T) T {
|
|
if value < min {
|
|
return min
|
|
}
|
|
if value > max {
|
|
return max
|
|
}
|
|
return value
|
|
}
|
|
|
|
// ContextWithTimeout creates a context with timeout
|
|
func ContextWithTimeout(timeout time.Duration) (context.Context, context.CancelFunc) {
|
|
return context.WithTimeout(context.Background(), timeout)
|
|
}
|
|
|
|
// MaskString masks a string showing only first and last n characters
|
|
func MaskString(s string, showChars int) string {
|
|
if len(s) <= showChars*2 {
|
|
return strings.Repeat("*", len(s))
|
|
}
|
|
return s[:showChars] + strings.Repeat("*", len(s)-showChars*2) + s[len(s)-showChars:]
|
|
}
|
|
|
|
// Retry executes a function with retries
|
|
func Retry(attempts int, sleep time.Duration, f func() error) error {
|
|
var err error
|
|
for i := 0; i < attempts; i++ {
|
|
if err = f(); err == nil {
|
|
return nil
|
|
}
|
|
if i < attempts-1 {
|
|
time.Sleep(sleep)
|
|
sleep *= 2 // Exponential backoff
|
|
}
|
|
}
|
|
return err
|
|
}
|