Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
# Bytes Util
Provide some common bytes util functions.
## Install
```shell
go get github.com/gookit/goutil/byteutil
```
## Go docs
- [Go docs](https://pkg.go.dev/github.com/gookit/goutil/byteutil)
## Functions API
> **Note**: doc by run `go doc ./byteutil`
```go
func AppendAny(dst []byte, v any) []byte
func FirstLine(bs []byte) []byte
func IsNumChar(c byte) bool
func Md5(src any) []byte
func Random(length int) ([]byte, error)
func SafeString(bs []byte, err error) string
func StrOrErr(bs []byte, err error) (string, error)
func String(b []byte) string
func ToString(b []byte) string
type Buffer struct{ ... }
func NewBuffer() *Buffer
type BytesEncoder interface{ ... }
type ChanPool struct{ ... }
func NewChanPool(maxSize int, width int, capWidth int) *ChanPool
type StdEncoder struct{ ... }
func NewStdEncoder(encFn func(src []byte) []byte, decFn func(src []byte) ([]byte, error)) *StdEncoder
```
## Code Check & Testing
```bash
gofmt -w -l ./
golint ./...
```
**Testing**:
```shell
go test -v ./byteutil/...
```
**Test limit by regexp**:
```shell
go test -v -run ^TestSetByKeys ./byteutil/...
```
+118
View File
@@ -0,0 +1,118 @@
package byteutil
import (
"bytes"
"fmt"
)
// Buffer wrap and extends the bytes.Buffer, add some useful methods
// and implements the io.Writer, io.Closer and stdio.Flusher interfaces
type Buffer struct {
bytes.Buffer
// custom error for testing
CloseErr error
FlushErr error
SyncErr error
}
// NewBuffer instance
func NewBuffer() *Buffer { return &Buffer{} }
// PrintByte to buffer, ignore error. alias of WriteByte()
func (b *Buffer) PrintByte(c byte) {
_ = b.WriteByte(c)
}
// WriteStr1 quiet write one string to buffer
func (b *Buffer) WriteStr1(s string) { b.writeStringNl(s, false) }
// WriteStr1Nl quiet write one string and end with newline
func (b *Buffer) WriteStr1Nl(s string) { b.writeStringNl(s, true) }
// writeStringNl quiet write one string and end with newline
func (b *Buffer) writeStringNl(s string, nl bool) {
_, _ = b.Buffer.WriteString(s)
if nl {
_ = b.WriteByte('\n')
}
}
// WriteStr quiet write strings to buffer
func (b *Buffer) WriteStr(ss ...string) {
b.writeStringsNl(ss, false)
}
// WriteStrings to buffer, ignore error.
func (b *Buffer) WriteStrings(ss []string) {
b.writeStringsNl(ss, false)
}
// WriteStringNl write message to buffer and end with newline
func (b *Buffer) WriteStringNl(ss ...string) {
b.writeStringsNl(ss, true)
}
// writeStringsNl to buffer, ignore error.
func (b *Buffer) writeStringsNl(ss []string, nl bool) {
for _, s := range ss {
_, _ = b.Buffer.WriteString(s)
}
if nl {
_ = b.WriteByte('\n')
}
}
// WriteAny type value to buffer
func (b *Buffer) WriteAny(vs ...any) {
b.writeAnysWithNl(vs, false)
}
// Writeln write values to buffer and end with newline
func (b *Buffer) Writeln(vs ...any) {
b.writeAnysWithNl(vs, true)
}
// WriteAnyNl type value to buffer and end with newline
func (b *Buffer) WriteAnyNl(vs ...any) {
b.writeAnysWithNl(vs, true)
}
// WriteAnyLn type value to buffer and end with newline
func (b *Buffer) writeAnysWithNl(vs []any, nl bool) {
for _, v := range vs {
_, _ = b.Buffer.WriteString(fmt.Sprint(v))
}
if nl {
_ = b.WriteByte('\n')
}
}
// Writef write message to buffer, ignore error. alias of Printf()
func (b *Buffer) Writef(tpl string, vs ...any) { _, _ = fmt.Fprintf(b, tpl, vs...) }
// Printf quick write message to buffer, ignore error.
func (b *Buffer) Printf(tpl string, vs ...any) { _, _ = fmt.Fprintf(b, tpl, vs...) }
// Println quick write message with newline to buffer, will ignore error.
func (b *Buffer) Println(vs ...any) { _, _ = fmt.Fprintln(b, vs...) }
// ResetGet buffer string. alias of ResetAndGet()
func (b *Buffer) ResetGet() string {
return b.ResetAndGet()
}
// ResetAndGet buffer string.
func (b *Buffer) ResetAndGet() string {
s := b.String()
b.Reset()
return s
}
// Close buffer
func (b *Buffer) Close() error { return b.CloseErr }
// Flush buffer
func (b *Buffer) Flush() error { return b.FlushErr }
// Sync anf flush buffer
func (b *Buffer) Sync() error { return b.SyncErr }
+125
View File
@@ -0,0 +1,125 @@
// Package byteutil provides some useful functions for byte slice.
package byteutil
import (
"bytes"
"crypto/md5"
"crypto/rand"
"encoding/hex"
"fmt"
"strconv"
"time"
)
// Md5 Generate a 32-bit md5 bytes
func Md5(src any) []byte {
bs := Md5Sum(src)
dst := make([]byte, hex.EncodedLen(len(bs)))
hex.Encode(dst, bs)
return dst
}
// Md5Sum Generate a md5 bytes
func Md5Sum(src any) []byte {
h := md5.New()
switch val := src.(type) {
case []byte:
h.Write(val)
case string:
h.Write([]byte(val))
default:
h.Write([]byte(fmt.Sprint(src)))
}
return h.Sum(nil) // cap(bs) == 16
}
// ShortMd5 Generate a 16-bit md5 bytes. remove the first 8 and last 8 bytes from 32-bit md5.
func ShortMd5(src any) []byte { return Md5(src)[8:24] }
// Random bytes generate
func Random(length int) ([]byte, error) {
b := make([]byte, length)
// Note that err == nil only if we read len(b) bytes.
if _, err := rand.Read(b); err != nil {
return nil, err
}
return b, nil
}
// FirstLine from command output
func FirstLine(bs []byte) []byte {
if i := bytes.IndexByte(bs, '\n'); i >= 0 {
return bs[0:i]
}
return bs
}
// AppendAny append any value to byte slice
func AppendAny(dst []byte, v any) []byte {
if v == nil {
return append(dst, "<nil>"...)
}
switch val := v.(type) {
case []byte:
dst = append(dst, val...)
case string:
dst = append(dst, val...)
case int:
dst = strconv.AppendInt(dst, int64(val), 10)
case int8:
dst = strconv.AppendInt(dst, int64(val), 10)
case int16:
dst = strconv.AppendInt(dst, int64(val), 10)
case int32:
dst = strconv.AppendInt(dst, int64(val), 10)
case int64:
dst = strconv.AppendInt(dst, val, 10)
case uint:
dst = strconv.AppendUint(dst, uint64(val), 10)
case uint8:
dst = strconv.AppendUint(dst, uint64(val), 10)
case uint16:
dst = strconv.AppendUint(dst, uint64(val), 10)
case uint32:
dst = strconv.AppendUint(dst, uint64(val), 10)
case uint64:
dst = strconv.AppendUint(dst, val, 10)
case float32:
dst = strconv.AppendFloat(dst, float64(val), 'f', -1, 32)
case float64:
dst = strconv.AppendFloat(dst, val, 'f', -1, 64)
case bool:
dst = strconv.AppendBool(dst, val)
case time.Time:
dst = val.AppendFormat(dst, time.RFC3339)
case time.Duration:
dst = strconv.AppendInt(dst, int64(val), 10)
case error:
dst = append(dst, val.Error()...)
case fmt.Stringer:
dst = append(dst, val.String()...)
default:
dst = append(dst, fmt.Sprint(v)...)
}
return dst
}
// Cut bytes by one byte char. like bytes.Cut(), but sep is byte.
func Cut(bs []byte, sep byte) (before, after []byte, found bool) {
return bytes.Cut(bs, []byte{sep})
}
// SafeCut bytes by one byte char. always return before and after
func SafeCut(bs []byte, sep byte) (before, after []byte) {
before, after, _ = bytes.Cut(bs, []byte{sep})
return
}
// SafeCuts bytes by sub bytes. like the bytes.Cut(), but always return before and after
func SafeCuts(bs []byte, sep []byte) (before, after []byte) {
before, after, _ = bytes.Cut(bs, sep)
return
}
+9
View File
@@ -0,0 +1,9 @@
package byteutil
// IsNumChar returns true if the given character is a numeric, otherwise false.
func IsNumChar(c byte) bool { return c >= '0' && c <= '9' }
// IsAlphaChar returns true if the given character is a alphabet, otherwise false.
func IsAlphaChar(c byte) bool {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}
+116
View File
@@ -0,0 +1,116 @@
package byteutil
import (
"fmt"
"strconv"
"time"
"unsafe"
"github.com/gookit/goutil/comdef"
)
// StrOrErr convert to string, return empty string on error.
func StrOrErr(bs []byte, err error) (string, error) {
if err != nil {
return "", err
}
return string(bs), err
}
// SafeString convert to string, return empty string on error.
func SafeString(bs []byte, err error) string {
if err != nil {
return ""
}
return string(bs)
}
// String unsafe convert bytes to string
func String(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
// ToString convert bytes to string
func ToString(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
// ToBytes convert any value to []byte. return error on convert failed.
func ToBytes(v any) ([]byte, error) {
return ToBytesWithFunc(v, nil)
}
// SafeBytes convert any value to []byte. use fmt.Sprint() on convert failed.
func SafeBytes(v any) []byte {
bs, _ := ToBytesWithFunc(v, func(v any) ([]byte, error) {
return []byte(fmt.Sprint(v)), nil
})
return bs
}
// ToBytesFunc convert any value to []byte
type ToBytesFunc = func(v any) ([]byte, error)
// ToBytesWithFunc convert any value to []byte with custom fallback func.
//
// refer the strutil.ToStringWithFunc
//
// On not convert:
// - If usrFn is nil, will return comdef.ErrConvType.
// - If usrFn is not nil, will call it to convert.
func ToBytesWithFunc(v any, usrFn ToBytesFunc) ([]byte, error) {
if v == nil {
return nil, nil
}
switch val := v.(type) {
case []byte:
return val, nil
case string:
return []byte(val), nil
case int:
return []byte(strconv.Itoa(val)), nil
case int8:
return []byte(strconv.Itoa(int(val))), nil
case int16:
return []byte(strconv.Itoa(int(val))), nil
case int32: // same as `rune`
return []byte(strconv.Itoa(int(val))), nil
case int64:
return []byte(strconv.FormatInt(val, 10)), nil
case uint:
return []byte(strconv.FormatUint(uint64(val), 10)), nil
case uint8:
return []byte(strconv.FormatUint(uint64(val), 10)), nil
case uint16:
return []byte(strconv.FormatUint(uint64(val), 10)), nil
case uint32:
return []byte(strconv.FormatUint(uint64(val), 10)), nil
case uint64:
return []byte(strconv.FormatUint(val, 10)), nil
case float32:
return []byte(strconv.FormatFloat(float64(val), 'f', -1, 32)), nil
case float64:
return []byte(strconv.FormatFloat(val, 'f', -1, 64)), nil
case bool:
return []byte(strconv.FormatBool(val)), nil
case time.Duration:
return []byte(strconv.FormatInt(int64(val), 10)), nil
case fmt.Stringer:
return []byte(val.String()), nil
case error:
return []byte(val.Error()), nil
default:
if usrFn == nil {
return nil, comdef.ErrConvType
}
return usrFn(val)
}
}
// Reverse 反转字节数组 eg: ABCD -> DCBA
func Reverse(arr []byte) {
for i := 0; i < len(arr)/2; i++ {
arr[i], arr[len(arr)-1-i] = arr[len(arr)-1-i], arr[i]
}
}
+69
View File
@@ -0,0 +1,69 @@
package byteutil
import (
"encoding/base64"
"encoding/hex"
)
// BytesEncodeFunc type
type BytesEncodeFunc func(src []byte) []byte
// BytesDecodeFunc type
type BytesDecodeFunc func(src []byte) ([]byte, error)
// BytesEncoder interface
type BytesEncoder interface {
Encode(src []byte) []byte
Decode(src []byte) ([]byte, error)
}
// StdEncoder implement the BytesEncoder
type StdEncoder struct {
encodeFn BytesEncodeFunc
decodeFn BytesDecodeFunc
}
// NewStdEncoder instance
func NewStdEncoder(encFn BytesEncodeFunc, decFn BytesDecodeFunc) *StdEncoder {
return &StdEncoder{
encodeFn: encFn,
decodeFn: decFn,
}
}
// Encode input
func (e *StdEncoder) Encode(src []byte) []byte {
return e.encodeFn(src)
}
// Decode input
func (e *StdEncoder) Decode(src []byte) ([]byte, error) {
return e.decodeFn(src)
}
var (
// HexEncoder instance
HexEncoder = NewStdEncoder(func(src []byte) []byte {
dst := make([]byte, hex.EncodedLen(len(src)))
hex.Encode(dst, src)
return dst
}, func(src []byte) ([]byte, error) {
n, err := hex.Decode(src, src)
return src[:n], err
})
// B64Encoder instance
B64Encoder = NewStdEncoder(func(src []byte) []byte {
b64Dst := make([]byte, base64.StdEncoding.EncodedLen(len(src)))
base64.StdEncoding.Encode(b64Dst, src)
return b64Dst
}, func(src []byte) ([]byte, error) {
dBuf := make([]byte, base64.StdEncoding.DecodedLen(len(src)))
n, err := base64.StdEncoding.Decode(dBuf, src)
if err != nil {
return nil, err
}
return dBuf[:n], err
})
)
+63
View File
@@ -0,0 +1,63 @@
package byteutil
// ChanPool struct
//
// Usage:
//
// bp := strutil.NewByteChanPool(500, 1024, 1024)
// buf:=bp.Get()
// defer bp.Put(buf)
// // use buf do something ...
//
// refer https://www.flysnow.org/2020/08/21/golang-chan-byte-pool.html
// from https://github.com/minio/minio/blob/master/internal/bpool/bpool.go
type ChanPool struct {
c chan []byte
w int // init byte width
wcap int // set byte cap
}
// NewChanPool instance
func NewChanPool(chSize int, width int, capWidth int) *ChanPool {
return &ChanPool{
c: make(chan []byte, chSize),
w: width,
wcap: capWidth,
}
}
// Get gets a []byte from the BytePool, or creates a new one if none are
// available in the pool.
func (bp *ChanPool) Get() (b []byte) {
select {
case b = <-bp.c: // reuse existing buffer
default:
// create new buffer
if bp.wcap > 0 {
b = make([]byte, bp.w, bp.wcap)
} else {
b = make([]byte, bp.w)
}
}
return
}
// Put returns the given Buffer to the BytePool.
func (bp *ChanPool) Put(b []byte) {
select {
case bp.c <- b:
// buffer went back into pool
default:
// buffer didn't go back into pool, just discard
}
}
// Width returns the width of the byte arrays in this pool.
func (bp *ChanPool) Width() (n int) {
return bp.w
}
// WidthCap returns the cap width of the byte arrays in this pool.
func (bp *ChanPool) WidthCap() (n int) {
return bp.wcap
}