copy langext & termext from ffsclient
This commit is contained in:
9
langext/bool.go
Normal file
9
langext/bool.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package langext
|
||||
|
||||
func FormatBool(v bool, strTrue string, strFalse string) string {
|
||||
if v {
|
||||
return strTrue
|
||||
} else {
|
||||
return strFalse
|
||||
}
|
||||
}
|
@@ -1,6 +1,9 @@
|
||||
package langext
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func FormatBytesToSI(b uint64) string {
|
||||
const unit = 1000
|
||||
@@ -14,3 +17,30 @@ func FormatBytesToSI(b uint64) string {
|
||||
}
|
||||
return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp])
|
||||
}
|
||||
|
||||
func BytesXOR(a []byte, b []byte) ([]byte, error) {
|
||||
if len(a) != len(b) {
|
||||
return nil, errors.New("length mismatch")
|
||||
}
|
||||
|
||||
r := make([]byte, len(a))
|
||||
|
||||
for i := 0; i < len(a); i++ {
|
||||
r[i] = a[i] ^ b[i]
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func FormatBytes(b int64) string {
|
||||
const unit = 1024
|
||||
if b < unit {
|
||||
return fmt.Sprintf("%d B", b)
|
||||
}
|
||||
div, exp := int64(unit), 0
|
||||
for n := b / unit; n >= unit; n /= unit {
|
||||
div *= unit
|
||||
exp++
|
||||
}
|
||||
return fmt.Sprintf("%.1f %ciB", float64(b)/float64(div), "KMGTPE"[exp])
|
||||
}
|
||||
|
5
langext/generics.go
Normal file
5
langext/generics.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package langext
|
||||
|
||||
type IntConstraint interface {
|
||||
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
|
||||
}
|
65
langext/json.go
Normal file
65
langext/json.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package langext
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type H map[string]any
|
||||
|
||||
type A []any
|
||||
|
||||
func TryPrettyPrintJson(str string) string {
|
||||
var prettyJSON bytes.Buffer
|
||||
if err := json.Indent(&prettyJSON, []byte(str), "", " "); err != nil {
|
||||
return str
|
||||
}
|
||||
return prettyJSON.String()
|
||||
}
|
||||
|
||||
func PrettyPrintJson(str string) (string, bool) {
|
||||
var prettyJSON bytes.Buffer
|
||||
if err := json.Indent(&prettyJSON, []byte(str), "", " "); err != nil {
|
||||
return str, false
|
||||
}
|
||||
return prettyJSON.String(), true
|
||||
}
|
||||
|
||||
func PatchJson[JV string | []byte](rawjson JV, key string, value any) (JV, error) {
|
||||
var err error
|
||||
|
||||
var jsonpayload map[string]any
|
||||
err = json.Unmarshal([]byte(rawjson), &jsonpayload)
|
||||
if err != nil {
|
||||
return *new(JV), fmt.Errorf("failed to unmarshal payload: %w", err)
|
||||
}
|
||||
|
||||
jsonpayload[key] = value
|
||||
|
||||
newjson, err := json.Marshal(jsonpayload)
|
||||
if err != nil {
|
||||
return *new(JV), fmt.Errorf("failed to re-marshal payload: %w", err)
|
||||
}
|
||||
|
||||
return JV(newjson), nil
|
||||
}
|
||||
|
||||
func PatchRemJson[JV string | []byte](rawjson JV, key string) (JV, error) {
|
||||
var err error
|
||||
|
||||
var jsonpayload map[string]any
|
||||
err = json.Unmarshal([]byte(rawjson), &jsonpayload)
|
||||
if err != nil {
|
||||
return *new(JV), fmt.Errorf("failed to unmarshal payload: %w", err)
|
||||
}
|
||||
|
||||
delete(jsonpayload, key)
|
||||
|
||||
newjson, err := json.Marshal(jsonpayload)
|
||||
if err != nil {
|
||||
return *new(JV), fmt.Errorf("failed to re-marshal payload: %w", err)
|
||||
}
|
||||
|
||||
return JV(newjson), nil
|
||||
}
|
9
langext/maps.go
Normal file
9
langext/maps.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package langext
|
||||
|
||||
func MapKeyArr[T comparable, V any](v map[T]V) []T {
|
||||
result := make([]T, 0, len(v))
|
||||
for k := range v {
|
||||
result = append(result, k)
|
||||
}
|
||||
return result
|
||||
}
|
11
langext/os.go
Normal file
11
langext/os.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package langext
|
||||
|
||||
import "os"
|
||||
|
||||
func FileExists(filename string) bool {
|
||||
info, err := os.Stat(filename)
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return !info.IsDir()
|
||||
}
|
38
langext/rand.go
Normal file
38
langext/rand.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package langext
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"math"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func RandBytes(size int) []byte {
|
||||
b := make([]byte, size)
|
||||
_, err := io.ReadFull(rand.Reader, b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func RandBase62(rlen int) string {
|
||||
ecs := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
|
||||
bi52 := big.NewInt(int64(len(ecs)))
|
||||
|
||||
randMax := big.NewInt(math.MaxInt64)
|
||||
|
||||
r := ""
|
||||
|
||||
for i := 0; i < rlen; i++ {
|
||||
v, err := rand.Int(rand.Reader, randMax)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
r += string(ecs[v.Mod(v, bi52).Int64()])
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
@@ -61,3 +61,49 @@ func ConvertStringerArray[T fmt.Stringer](inarr []T) []string {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func StrRunePadLeft(str string, pad string, padlen int) string {
|
||||
if pad == "" {
|
||||
pad = " "
|
||||
}
|
||||
|
||||
if len([]rune(str)) >= padlen {
|
||||
return str
|
||||
}
|
||||
|
||||
return strings.Repeat(pad, padlen-len([]rune(str)))[0:(padlen-len([]rune(str)))] + str
|
||||
}
|
||||
|
||||
func StrRunePadRight(str string, pad string, padlen int) string {
|
||||
if pad == "" {
|
||||
pad = " "
|
||||
}
|
||||
|
||||
if len([]rune(str)) >= padlen {
|
||||
return str
|
||||
}
|
||||
|
||||
return str + strings.Repeat(pad, padlen-len([]rune(str)))[0:(padlen-len([]rune(str)))]
|
||||
}
|
||||
|
||||
func Indent(str string, pad string) string {
|
||||
eonl := strings.HasSuffix(str, "\n")
|
||||
r := ""
|
||||
for _, v := range strings.Split(str, "\n") {
|
||||
r += pad + v + "\n"
|
||||
}
|
||||
|
||||
if eonl {
|
||||
r = r[0 : len(r)-1]
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func NumToStringOpt[V IntConstraint](v *V, fallback string) string {
|
||||
if v == nil {
|
||||
return fallback
|
||||
} else {
|
||||
return fmt.Sprintf("%d", v)
|
||||
}
|
||||
}
|
||||
|
134
langext/uuid.go
Normal file
134
langext/uuid.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package langext
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func NewUUID() ([16]byte, error) {
|
||||
var uuid [16]byte
|
||||
_, err := io.ReadFull(rand.Reader, uuid[:])
|
||||
if err != nil {
|
||||
return [16]byte{}, err
|
||||
}
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
func NewHexUUID() (string, error) {
|
||||
uuid, err := NewUUID()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Result: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
|
||||
var dst = make([]byte, 36)
|
||||
|
||||
hex.Encode(dst, uuid[:4])
|
||||
dst[8] = '-'
|
||||
hex.Encode(dst[9:13], uuid[4:6])
|
||||
dst[13] = '-'
|
||||
hex.Encode(dst[14:18], uuid[6:8])
|
||||
dst[18] = '-'
|
||||
hex.Encode(dst[19:23], uuid[8:10])
|
||||
dst[23] = '-'
|
||||
hex.Encode(dst[24:], uuid[10:])
|
||||
|
||||
return string(dst), nil
|
||||
}
|
||||
|
||||
func NewUpperHexUUID() (string, error) {
|
||||
uuid, err := NewUUID()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Result: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
||||
|
||||
var dst = make([]byte, 36)
|
||||
|
||||
hex.Encode(dst, uuid[:4])
|
||||
dst[8] = '-'
|
||||
hex.Encode(dst[9:13], uuid[4:6])
|
||||
dst[13] = '-'
|
||||
hex.Encode(dst[14:18], uuid[6:8])
|
||||
dst[18] = '-'
|
||||
hex.Encode(dst[19:23], uuid[8:10])
|
||||
dst[23] = '-'
|
||||
hex.Encode(dst[24:], uuid[10:])
|
||||
|
||||
return strings.ToUpper(string(dst)), nil
|
||||
}
|
||||
|
||||
func NewRawHexUUID() (string, error) {
|
||||
uuid, err := NewUUID()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Result: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
var dst = make([]byte, 32)
|
||||
|
||||
hex.Encode(dst, uuid[:4])
|
||||
hex.Encode(dst[8:12], uuid[4:6])
|
||||
hex.Encode(dst[12:16], uuid[6:8])
|
||||
hex.Encode(dst[16:20], uuid[8:10])
|
||||
hex.Encode(dst[20:], uuid[10:])
|
||||
|
||||
return strings.ToUpper(string(dst)), nil
|
||||
}
|
||||
|
||||
func NewBracesUUID() (string, error) {
|
||||
uuid, err := NewUUID()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Result: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
|
||||
|
||||
var dst = make([]byte, 38)
|
||||
|
||||
dst[0] = '{'
|
||||
hex.Encode(dst, uuid[:5])
|
||||
dst[9] = '-'
|
||||
hex.Encode(dst[10:14], uuid[4:6])
|
||||
dst[14] = '-'
|
||||
hex.Encode(dst[15:19], uuid[6:8])
|
||||
dst[19] = '-'
|
||||
hex.Encode(dst[20:24], uuid[8:10])
|
||||
dst[24] = '-'
|
||||
hex.Encode(dst[25:], uuid[10:])
|
||||
dst[37] = '}'
|
||||
|
||||
return strings.ToUpper(string(dst)), nil
|
||||
}
|
||||
|
||||
func NewParensUUID() (string, error) {
|
||||
uuid, err := NewUUID()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Result: (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)
|
||||
|
||||
var dst = make([]byte, 38)
|
||||
|
||||
dst[0] = '('
|
||||
hex.Encode(dst, uuid[:5])
|
||||
dst[9] = '-'
|
||||
hex.Encode(dst[10:14], uuid[4:6])
|
||||
dst[14] = '-'
|
||||
hex.Encode(dst[15:19], uuid[6:8])
|
||||
dst[19] = '-'
|
||||
hex.Encode(dst[20:24], uuid[8:10])
|
||||
dst[24] = '-'
|
||||
hex.Encode(dst[25:], uuid[10:])
|
||||
dst[37] = ')'
|
||||
|
||||
return strings.ToUpper(string(dst)), nil
|
||||
}
|
Reference in New Issue
Block a user