mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-29 02:52:26 -05:00
[chore] use our own logging implementation (#716)
* first commit
Signed-off-by: kim <grufwub@gmail.com>
* replace logging with our own log library
Signed-off-by: kim <grufwub@gmail.com>
* fix imports
Signed-off-by: kim <grufwub@gmail.com>
* fix log imports
Signed-off-by: kim <grufwub@gmail.com>
* add license text
Signed-off-by: kim <grufwub@gmail.com>
* fix package import cycle between config and log package
Signed-off-by: kim <grufwub@gmail.com>
* fix empty kv.Fields{} being passed to WithFields()
Signed-off-by: kim <grufwub@gmail.com>
* fix uses of log.WithFields() with whitespace issues and empty slices
Signed-off-by: kim <grufwub@gmail.com>
* *linter related grumbling*
Signed-off-by: kim <grufwub@gmail.com>
* gofmt the codebase! also fix more log.WithFields() formatting issues
Signed-off-by: kim <grufwub@gmail.com>
* update testrig code to match new changes
Signed-off-by: kim <grufwub@gmail.com>
* fix error wrapping in non fmt.Errorf function
Signed-off-by: kim <grufwub@gmail.com>
* add benchmarking of log.Caller() vs non-cached
Signed-off-by: kim <grufwub@gmail.com>
* fix syslog tests, add standard build tags to test runner to ensure consistency
Signed-off-by: kim <grufwub@gmail.com>
* make syslog tests more robust
Signed-off-by: kim <grufwub@gmail.com>
* fix caller depth arithmatic (is that how you spell it?)
Signed-off-by: kim <grufwub@gmail.com>
* update to use unkeyed fields in kv.Field{} instances
Signed-off-by: kim <grufwub@gmail.com>
* update go-kv library
Signed-off-by: kim <grufwub@gmail.com>
* update libraries list
Signed-off-by: kim <grufwub@gmail.com>
* fuck you linter get nerfed
Signed-off-by: kim <grufwub@gmail.com>
Co-authored-by: tobi <31960611+tsmethurst@users.noreply.github.com>
This commit is contained in:
parent
59be7466f3
commit
098dbe6ff4
141 changed files with 3046 additions and 997 deletions
5
vendor/codeberg.org/gruf/go-kv/format/README.md
generated
vendored
Normal file
5
vendor/codeberg.org/gruf/go-kv/format/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
String formatting package using Rust-style formatting directives, geared specifcally towards formatting arguments for key-value log output. Provides ONLY default, key, value and verbose formatting directives. For most formatting cases you will be best served by `"fmt"`.
|
||||
|
||||
Generally more visually friendly than `"fmt"` and performance is much improved.
|
||||
|
||||

|
||||
BIN
vendor/codeberg.org/gruf/go-kv/format/benchmark.png
generated
vendored
Normal file
BIN
vendor/codeberg.org/gruf/go-kv/format/benchmark.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
922
vendor/codeberg.org/gruf/go-kv/format/format.go
generated
vendored
Normal file
922
vendor/codeberg.org/gruf/go-kv/format/format.go
generated
vendored
Normal file
|
|
@ -0,0 +1,922 @@
|
|||
package format
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"unicode/utf8"
|
||||
|
||||
"codeberg.org/gruf/go-byteutil"
|
||||
)
|
||||
|
||||
const (
|
||||
// Flag bit constants, note they are prioritised in this order.
|
||||
IsKeyBit = uint8(1) << 0 // set to indicate key formatting
|
||||
VboseBit = uint8(1) << 1 // set to indicate verbose formatting
|
||||
IsValBit = uint8(1) << 2 // set to indicate value formatting
|
||||
PanicBit = uint8(1) << 3 // set after panic to prevent recursion
|
||||
)
|
||||
|
||||
// format provides formatting of values into a Buffer.
|
||||
type format struct {
|
||||
// Flags are the currently set value flags.
|
||||
Flags uint8
|
||||
|
||||
// Derefs is the current value dereference count.
|
||||
Derefs uint8
|
||||
|
||||
// CurDepth is the current Format iterator depth.
|
||||
CurDepth uint8
|
||||
|
||||
// VType is the current value type.
|
||||
VType string
|
||||
|
||||
// Config is the set Formatter config (MUST NOT be nil).
|
||||
Config *Formatter
|
||||
|
||||
// Buffer is the currently set output buffer.
|
||||
Buffer *byteutil.Buffer
|
||||
}
|
||||
|
||||
// AtMaxDepth returns whether format is currently at max depth.
|
||||
func (f format) AtMaxDepth() bool {
|
||||
return f.CurDepth > f.Config.MaxDepth
|
||||
}
|
||||
|
||||
// Key returns whether the isKey flag is set.
|
||||
func (f format) Key() bool {
|
||||
return (f.Flags & IsKeyBit) != 0
|
||||
}
|
||||
|
||||
// Value returns whether the isVal flag is set.
|
||||
func (f format) Value() bool {
|
||||
return (f.Flags & IsValBit) != 0
|
||||
}
|
||||
|
||||
// Verbose returns whether the verbose flag is set.
|
||||
func (f format) Verbose() bool {
|
||||
return (f.Flags & VboseBit) != 0
|
||||
}
|
||||
|
||||
// Panic returns whether the panic flag is set.
|
||||
func (f format) Panic() bool {
|
||||
return (f.Flags & PanicBit) != 0
|
||||
}
|
||||
|
||||
// SetKey returns format instance with the IsKey bit set to true,
|
||||
// note this resets the dereference count.
|
||||
func (f format) SetKey() format {
|
||||
flags := f.Flags | IsKeyBit
|
||||
flags &= ^IsValBit
|
||||
return format{
|
||||
Flags: flags,
|
||||
CurDepth: f.CurDepth,
|
||||
Config: f.Config,
|
||||
Buffer: f.Buffer,
|
||||
}
|
||||
}
|
||||
|
||||
// SetValue returns format instance with the IsVal bit set to true,
|
||||
// note this resets the dereference count.
|
||||
func (f format) SetValue() format {
|
||||
flags := f.Flags | IsValBit
|
||||
flags &= ^IsKeyBit
|
||||
return format{
|
||||
Flags: flags,
|
||||
CurDepth: f.CurDepth,
|
||||
Config: f.Config,
|
||||
Buffer: f.Buffer,
|
||||
}
|
||||
}
|
||||
|
||||
// SetVerbose returns format instance with the Vbose bit set to true,
|
||||
// note this resets the dereference count.
|
||||
func (f format) SetVerbose() format {
|
||||
return format{
|
||||
Flags: f.Flags | VboseBit,
|
||||
CurDepth: f.CurDepth,
|
||||
Config: f.Config,
|
||||
Buffer: f.Buffer,
|
||||
}
|
||||
}
|
||||
|
||||
// SetPanic returns format instance with the panic bit set to true,
|
||||
// note this resets the dereference count and sets IsVal (unsetting IsKey) bit.
|
||||
func (f format) SetPanic() format {
|
||||
flags := f.Flags | PanicBit
|
||||
flags |= IsValBit
|
||||
flags &= ^IsKeyBit
|
||||
return format{
|
||||
Flags: flags,
|
||||
CurDepth: f.CurDepth,
|
||||
Config: f.Config,
|
||||
Buffer: f.Buffer,
|
||||
}
|
||||
}
|
||||
|
||||
// IncrDepth returns format instance with depth incremented and derefs reset.
|
||||
func (f format) IncrDepth() format {
|
||||
return format{
|
||||
Flags: f.Flags,
|
||||
Derefs: f.Derefs,
|
||||
CurDepth: f.CurDepth + 1,
|
||||
Config: f.Config,
|
||||
Buffer: f.Buffer,
|
||||
}
|
||||
}
|
||||
|
||||
// IncrDerefs returns format instance with dereference count incremented.
|
||||
func (f format) IncrDerefs() format {
|
||||
return format{
|
||||
Flags: f.Flags,
|
||||
Derefs: f.Derefs + 1,
|
||||
CurDepth: f.CurDepth,
|
||||
Config: f.Config,
|
||||
Buffer: f.Buffer,
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendType() {
|
||||
const derefs = `********************************` +
|
||||
`********************************` +
|
||||
`********************************` +
|
||||
`********************************` +
|
||||
`********************************` +
|
||||
`********************************` +
|
||||
`********************************` +
|
||||
`********************************`
|
||||
f.Buffer.B = append(f.Buffer.B, derefs[:f.Derefs]...)
|
||||
f.Buffer.B = append(f.Buffer.B, f.VType...)
|
||||
}
|
||||
|
||||
func (f format) AppendNil() {
|
||||
if !f.Verbose() {
|
||||
f.Buffer.B = append(f.Buffer.B, `nil`...)
|
||||
return
|
||||
}
|
||||
|
||||
// Append nil with type
|
||||
f.Buffer.B = append(f.Buffer.B, '(')
|
||||
f.AppendType()
|
||||
f.Buffer.B = append(f.Buffer.B, `)(nil`...)
|
||||
f.Buffer.B = append(f.Buffer.B, ')')
|
||||
}
|
||||
|
||||
func (f format) AppendByte(b byte) {
|
||||
switch {
|
||||
// Always quoted
|
||||
case f.Key():
|
||||
f.Buffer.B = append(f.Buffer.B, '\'')
|
||||
f.Buffer.B = append(f.Buffer.B, byte2str(b)...)
|
||||
f.Buffer.B = append(f.Buffer.B, '\'')
|
||||
|
||||
// Always quoted ASCII with type
|
||||
case f.Verbose():
|
||||
f._AppendPrimitiveTyped(func(f format) {
|
||||
f.Buffer.B = append(f.Buffer.B, '\'')
|
||||
f.Buffer.B = append(f.Buffer.B, byte2str(b)...)
|
||||
f.Buffer.B = append(f.Buffer.B, '\'')
|
||||
})
|
||||
|
||||
// Always quoted
|
||||
case f.Value():
|
||||
f.Buffer.B = append(f.Buffer.B, '\'')
|
||||
f.Buffer.B = append(f.Buffer.B, byte2str(b)...)
|
||||
f.Buffer.B = append(f.Buffer.B, '\'')
|
||||
|
||||
// Append as raw byte
|
||||
default:
|
||||
f.Buffer.B = append(f.Buffer.B, b)
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendBytes(b []byte) {
|
||||
switch {
|
||||
// Bytes CAN be nil formatted
|
||||
case b == nil:
|
||||
f.AppendNil()
|
||||
|
||||
// Handle bytes as string key
|
||||
case f.Key():
|
||||
f.AppendStringKey(b2s(b))
|
||||
|
||||
// Append as separate ASCII quoted bytes in slice
|
||||
case f.Verbose():
|
||||
f._AppendArrayTyped(func(f format) {
|
||||
for i := 0; i < len(b); i++ {
|
||||
f.Buffer.B = append(f.Buffer.B, '\'')
|
||||
f.Buffer.B = append(f.Buffer.B, byte2str(b[i])...)
|
||||
f.Buffer.B = append(f.Buffer.B, `',`...)
|
||||
}
|
||||
if len(b) > 0 {
|
||||
f.Buffer.Truncate(1)
|
||||
}
|
||||
})
|
||||
|
||||
// Append as quoted string
|
||||
case f.Value():
|
||||
f.AppendStringQuoted(b2s(b))
|
||||
|
||||
// Append as raw bytes
|
||||
default:
|
||||
f.Buffer.B = append(f.Buffer.B, b...)
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendRune(r rune) {
|
||||
switch {
|
||||
// Quoted only if spaces/requires escaping
|
||||
case f.Key():
|
||||
f.AppendRuneKey(r)
|
||||
|
||||
// Always quoted ASCII with type
|
||||
case f.Verbose():
|
||||
f._AppendPrimitiveTyped(func(f format) {
|
||||
f.Buffer.B = strconv.AppendQuoteRuneToASCII(f.Buffer.B, r)
|
||||
})
|
||||
|
||||
// Always quoted value
|
||||
case f.Value():
|
||||
f.Buffer.B = strconv.AppendQuoteRune(f.Buffer.B, r)
|
||||
|
||||
// Append as raw rune
|
||||
default:
|
||||
f.Buffer.WriteRune(r)
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendRuneKey(r rune) {
|
||||
if utf8.RuneLen(r) > 1 && (r < ' ' && r != '\t') || r == '`' || r == '\u007F' {
|
||||
// Quote and escape this rune
|
||||
f.Buffer.B = strconv.AppendQuoteRuneToASCII(f.Buffer.B, r)
|
||||
} else {
|
||||
// Simply append rune
|
||||
f.Buffer.WriteRune(r)
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendRunes(r []rune) {
|
||||
switch {
|
||||
// Runes CAN be nil formatted
|
||||
case r == nil:
|
||||
f.AppendNil()
|
||||
|
||||
// Handle bytes as string key
|
||||
case f.Key():
|
||||
f.AppendStringKey(string(r))
|
||||
|
||||
// Append as separate ASCII quoted bytes in slice
|
||||
case f.Verbose():
|
||||
f._AppendArrayTyped(func(f format) {
|
||||
for i := 0; i < len(r); i++ {
|
||||
f.Buffer.B = strconv.AppendQuoteRuneToASCII(f.Buffer.B, r[i])
|
||||
f.Buffer.B = append(f.Buffer.B, ',')
|
||||
}
|
||||
if len(r) > 0 {
|
||||
f.Buffer.Truncate(1)
|
||||
}
|
||||
})
|
||||
|
||||
// Append as quoted string
|
||||
case f.Value():
|
||||
f.AppendStringQuoted(string(r))
|
||||
|
||||
// Append as raw bytes
|
||||
default:
|
||||
for i := 0; i < len(r); i++ {
|
||||
f.Buffer.WriteRune(r[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendString(s string) {
|
||||
switch {
|
||||
// Quoted only if spaces/requires escaping
|
||||
case f.Key():
|
||||
f.AppendStringKey(s)
|
||||
|
||||
// Always quoted with type
|
||||
case f.Verbose():
|
||||
f._AppendPrimitiveTyped(func(f format) {
|
||||
f.AppendStringQuoted(s)
|
||||
})
|
||||
|
||||
// Always quoted string
|
||||
case f.Value():
|
||||
f.AppendStringQuoted(s)
|
||||
|
||||
// All else
|
||||
default:
|
||||
f.Buffer.B = append(f.Buffer.B, s...)
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendStringKey(s string) {
|
||||
if !strconv.CanBackquote(s) {
|
||||
// Requires quoting AND escaping
|
||||
f.Buffer.B = strconv.AppendQuote(f.Buffer.B, s)
|
||||
} else if ContainsDoubleQuote(s) {
|
||||
// Contains double quotes, needs escaping
|
||||
f.Buffer.B = AppendEscape(f.Buffer.B, s)
|
||||
} else if len(s) < 1 || ContainsSpaceOrTab(s) {
|
||||
// Contains space, needs quotes
|
||||
f.Buffer.B = append(f.Buffer.B, '"')
|
||||
f.Buffer.B = append(f.Buffer.B, s...)
|
||||
f.Buffer.B = append(f.Buffer.B, '"')
|
||||
} else {
|
||||
// All else write as-is
|
||||
f.Buffer.B = append(f.Buffer.B, s...)
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendStringQuoted(s string) {
|
||||
if !strconv.CanBackquote(s) {
|
||||
// Requires quoting AND escaping
|
||||
f.Buffer.B = strconv.AppendQuote(f.Buffer.B, s)
|
||||
} else if ContainsDoubleQuote(s) {
|
||||
// Contains double quotes, needs escaping
|
||||
f.Buffer.B = append(f.Buffer.B, '"')
|
||||
f.Buffer.B = AppendEscape(f.Buffer.B, s)
|
||||
f.Buffer.B = append(f.Buffer.B, '"')
|
||||
} else {
|
||||
// Simply append with quotes
|
||||
f.Buffer.B = append(f.Buffer.B, '"')
|
||||
f.Buffer.B = append(f.Buffer.B, s...)
|
||||
f.Buffer.B = append(f.Buffer.B, '"')
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendBool(b bool) {
|
||||
if f.Verbose() {
|
||||
// Append as bool with type information
|
||||
f._AppendPrimitiveTyped(func(f format) {
|
||||
f.Buffer.B = strconv.AppendBool(f.Buffer.B, b)
|
||||
})
|
||||
} else {
|
||||
// Simply append as bool
|
||||
f.Buffer.B = strconv.AppendBool(f.Buffer.B, b)
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendInt(i int64) {
|
||||
f._AppendPrimitiveType(func(f format) {
|
||||
f.Buffer.B = strconv.AppendInt(f.Buffer.B, i, 10)
|
||||
})
|
||||
}
|
||||
|
||||
func (f format) AppendUint(u uint64) {
|
||||
f._AppendPrimitiveType(func(f format) {
|
||||
f.Buffer.B = strconv.AppendUint(f.Buffer.B, u, 10)
|
||||
})
|
||||
}
|
||||
|
||||
func (f format) AppendFloat(l float64) {
|
||||
f._AppendPrimitiveType(func(f format) {
|
||||
f.AppendFloatValue(l)
|
||||
})
|
||||
}
|
||||
|
||||
func (f format) AppendFloatValue(l float64) {
|
||||
f.Buffer.B = strconv.AppendFloat(f.Buffer.B, l, 'f', -1, 64)
|
||||
}
|
||||
|
||||
func (f format) AppendComplex(c complex128) {
|
||||
f._AppendPrimitiveType(func(f format) {
|
||||
f.AppendFloatValue(real(c))
|
||||
f.Buffer.B = append(f.Buffer.B, '+')
|
||||
f.AppendFloatValue(imag(c))
|
||||
f.Buffer.B = append(f.Buffer.B, 'i')
|
||||
})
|
||||
}
|
||||
|
||||
func (f format) AppendPtr(u uint64) {
|
||||
f._AppendPtrType(func(f format) {
|
||||
if u == 0 {
|
||||
// Append as nil
|
||||
f.Buffer.B = append(f.Buffer.B, `nil`...)
|
||||
} else {
|
||||
// Append as hex number
|
||||
f.Buffer.B = append(f.Buffer.B, `0x`...)
|
||||
f.Buffer.B = strconv.AppendUint(f.Buffer.B, u, 16)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (f format) AppendInterfaceOrReflect(i interface{}) {
|
||||
if !f.AppendInterface(i) {
|
||||
// Interface append failed, used reflected value + type
|
||||
f.AppendReflectValue(reflect.ValueOf(i), reflect.TypeOf(i))
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendInterfaceOrReflectNext(v reflect.Value, t reflect.Type) {
|
||||
// Check we haven't hit max
|
||||
if f.AtMaxDepth() {
|
||||
f.Buffer.B = append(f.Buffer.B, `...`...)
|
||||
return
|
||||
}
|
||||
|
||||
// Incr the depth
|
||||
f = f.IncrDepth()
|
||||
|
||||
// Make actual call
|
||||
f.AppendReflectOrInterface(v, t)
|
||||
}
|
||||
|
||||
func (f format) AppendReflectOrInterface(v reflect.Value, t reflect.Type) {
|
||||
if !v.CanInterface() ||
|
||||
!f.AppendInterface(v.Interface()) {
|
||||
// Interface append failed, use reflect
|
||||
f.AppendReflectValue(v, t)
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendInterface(i interface{}) bool {
|
||||
switch i := i.(type) {
|
||||
// Reflect types
|
||||
case reflect.Type:
|
||||
f.AppendReflectType(i)
|
||||
case reflect.Value:
|
||||
f.Buffer.B = append(f.Buffer.B, `reflect.Value`...)
|
||||
f.Buffer.B = append(f.Buffer.B, '(')
|
||||
f.Buffer.B = append(f.Buffer.B, i.String()...)
|
||||
f.Buffer.B = append(f.Buffer.B, ')')
|
||||
|
||||
// Bytes, runes and string types
|
||||
case rune:
|
||||
f.VType = `int32`
|
||||
f.AppendRune(i)
|
||||
case []rune:
|
||||
f.VType = `[]int32`
|
||||
f.AppendRunes(i)
|
||||
case byte:
|
||||
f.VType = `uint8`
|
||||
f.AppendByte(i)
|
||||
case []byte:
|
||||
f.VType = `[]uint8`
|
||||
f.AppendBytes(i)
|
||||
case string:
|
||||
f.VType = `string`
|
||||
f.AppendString(i)
|
||||
|
||||
// Int types
|
||||
case int:
|
||||
f.VType = `int`
|
||||
f.AppendInt(int64(i))
|
||||
case int8:
|
||||
f.VType = `int8`
|
||||
f.AppendInt(int64(i))
|
||||
case int16:
|
||||
f.VType = `int16`
|
||||
f.AppendInt(int64(i))
|
||||
case int64:
|
||||
f.VType = `int64`
|
||||
f.AppendInt(int64(i))
|
||||
|
||||
// Uint types
|
||||
case uint:
|
||||
f.VType = `uint`
|
||||
f.AppendUint(uint64(i))
|
||||
case uint16:
|
||||
f.VType = `uint16`
|
||||
f.AppendUint(uint64(i))
|
||||
case uint32:
|
||||
f.VType = `uint32`
|
||||
f.AppendUint(uint64(i))
|
||||
case uint64:
|
||||
f.VType = `uint64`
|
||||
f.AppendUint(uint64(i))
|
||||
|
||||
// Float types
|
||||
case float32:
|
||||
f.VType = `float32`
|
||||
f.AppendFloat(float64(i))
|
||||
case float64:
|
||||
f.VType = `float64`
|
||||
f.AppendFloat(float64(i))
|
||||
|
||||
// Bool type
|
||||
case bool:
|
||||
f.VType = `bool`
|
||||
f.AppendBool(i)
|
||||
|
||||
// Complex types
|
||||
case complex64:
|
||||
f.VType = `complex64`
|
||||
f.AppendComplex(complex128(i))
|
||||
case complex128:
|
||||
f.VType = `complex128`
|
||||
f.AppendComplex(complex128(i))
|
||||
|
||||
// Method types
|
||||
case error:
|
||||
return f._AppendMethodType(func() string {
|
||||
return i.Error()
|
||||
}, i)
|
||||
case interface{ String() string }:
|
||||
return f._AppendMethodType(func() string {
|
||||
return i.String()
|
||||
}, i)
|
||||
|
||||
// No quick handler
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (f format) AppendReflectType(t reflect.Type) {
|
||||
switch f.VType = `reflect.Type`; {
|
||||
case isNil(t) /* safer nil check */ :
|
||||
f.AppendNil()
|
||||
case f.Verbose():
|
||||
f.AppendType()
|
||||
f.Buffer.B = append(f.Buffer.B, '(')
|
||||
f.Buffer.B = append(f.Buffer.B, t.String()...)
|
||||
f.Buffer.B = append(f.Buffer.B, ')')
|
||||
default:
|
||||
f.Buffer.B = append(f.Buffer.B, t.String()...)
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendReflectValue(v reflect.Value, t reflect.Type) {
|
||||
switch v.Kind() {
|
||||
// String/byte types
|
||||
case reflect.String:
|
||||
f.VType = t.String()
|
||||
f.AppendString(v.String())
|
||||
case reflect.Uint8:
|
||||
f.VType = t.String()
|
||||
f.AppendByte(byte(v.Uint()))
|
||||
case reflect.Int32:
|
||||
f.VType = t.String()
|
||||
f.AppendRune(rune(v.Int()))
|
||||
|
||||
// Float tpyes
|
||||
case reflect.Float32, reflect.Float64:
|
||||
f.VType = t.String()
|
||||
f.AppendFloat(v.Float())
|
||||
|
||||
// Int types
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int64:
|
||||
f.VType = t.String()
|
||||
f.AppendInt(v.Int())
|
||||
|
||||
// Uint types
|
||||
case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
f.VType = t.String()
|
||||
f.AppendUint(v.Uint())
|
||||
|
||||
// Complex types
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
f.VType = t.String()
|
||||
f.AppendComplex(v.Complex())
|
||||
|
||||
// Bool type
|
||||
case reflect.Bool:
|
||||
f.VType = t.String()
|
||||
f.AppendBool(v.Bool())
|
||||
|
||||
// Slice and array types
|
||||
case reflect.Array:
|
||||
f.AppendArray(v, t)
|
||||
case reflect.Slice:
|
||||
f.AppendSlice(v, t)
|
||||
|
||||
// Map types
|
||||
case reflect.Map:
|
||||
f.AppendMap(v, t)
|
||||
|
||||
// Struct types
|
||||
case reflect.Struct:
|
||||
f.AppendStruct(v, t)
|
||||
|
||||
// Interface type
|
||||
case reflect.Interface:
|
||||
if v.IsNil() {
|
||||
// Append nil ptr type
|
||||
f.VType = t.String()
|
||||
f.AppendNil()
|
||||
} else {
|
||||
// Append interface
|
||||
v = v.Elem()
|
||||
t = v.Type()
|
||||
f.AppendReflectOrInterface(v, t)
|
||||
}
|
||||
|
||||
// Deref'able ptr type
|
||||
case reflect.Ptr:
|
||||
if v.IsNil() {
|
||||
// Append nil ptr type
|
||||
f.VType = t.String()
|
||||
f.AppendNil()
|
||||
} else {
|
||||
// Deref to next level
|
||||
f = f.IncrDerefs()
|
||||
v, t = v.Elem(), t.Elem()
|
||||
f.AppendReflectOrInterface(v, t)
|
||||
}
|
||||
|
||||
// 'raw' pointer types
|
||||
case reflect.UnsafePointer, reflect.Func, reflect.Chan:
|
||||
f.VType = t.String()
|
||||
f.AppendPtr(uint64(v.Pointer()))
|
||||
case reflect.Uintptr:
|
||||
f.VType = t.String()
|
||||
f.AppendPtr(v.Uint())
|
||||
|
||||
// Zero reflect value
|
||||
case reflect.Invalid:
|
||||
f.Buffer.B = append(f.Buffer.B, `nil`...)
|
||||
|
||||
// All others
|
||||
default:
|
||||
f.VType = t.String()
|
||||
f.AppendType()
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendSlice(v reflect.Value, t reflect.Type) {
|
||||
// Get slice value type
|
||||
f.VType = t.String()
|
||||
|
||||
if t.Elem().Kind() == reflect.Uint8 {
|
||||
// This is a byte slice
|
||||
f.AppendBytes(v.Bytes())
|
||||
return
|
||||
}
|
||||
|
||||
if v.IsNil() {
|
||||
// Nil slice
|
||||
f.AppendNil()
|
||||
return
|
||||
}
|
||||
|
||||
if f.Verbose() {
|
||||
// Append array with type information
|
||||
f._AppendArrayTyped(func(f format) {
|
||||
f.AppendArrayElems(v, t)
|
||||
})
|
||||
} else {
|
||||
// Simply append array as elems
|
||||
f._AppendArray(func(f format) {
|
||||
f.AppendArrayElems(v, t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendArray(v reflect.Value, t reflect.Type) {
|
||||
// Get array value type
|
||||
f.VType = t.String()
|
||||
|
||||
if f.Verbose() {
|
||||
// Append array with type information
|
||||
f._AppendArrayTyped(func(f format) {
|
||||
f.AppendArrayElems(v, t)
|
||||
})
|
||||
} else {
|
||||
// Simply append array as elems
|
||||
f._AppendArray(func(f format) {
|
||||
f.AppendArrayElems(v, t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendArrayElems(v reflect.Value, t reflect.Type) {
|
||||
// Get no. elems
|
||||
n := v.Len()
|
||||
|
||||
// Get elem type
|
||||
et := t.Elem()
|
||||
|
||||
// Append values
|
||||
for i := 0; i < n; i++ {
|
||||
f.SetValue().AppendInterfaceOrReflectNext(v.Index(i), et)
|
||||
f.Buffer.B = append(f.Buffer.B, ',')
|
||||
}
|
||||
|
||||
// Drop last comma
|
||||
if n > 0 {
|
||||
f.Buffer.Truncate(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendMap(v reflect.Value, t reflect.Type) {
|
||||
// Get value type
|
||||
f.VType = t.String()
|
||||
|
||||
if v.IsNil() {
|
||||
// Nil map -- no fields
|
||||
f.AppendNil()
|
||||
return
|
||||
}
|
||||
|
||||
// Append field formatted map fields
|
||||
f._AppendFieldType(func(f format) {
|
||||
f.AppendMapFields(v, t)
|
||||
})
|
||||
}
|
||||
|
||||
func (f format) AppendMapFields(v reflect.Value, t reflect.Type) {
|
||||
// Get a map iterator
|
||||
r := v.MapRange()
|
||||
n := v.Len()
|
||||
|
||||
// Get key/val types
|
||||
kt := t.Key()
|
||||
kv := t.Elem()
|
||||
|
||||
// Iterate pairs
|
||||
for r.Next() {
|
||||
f.SetKey().AppendInterfaceOrReflectNext(r.Key(), kt)
|
||||
f.Buffer.B = append(f.Buffer.B, '=')
|
||||
f.SetValue().AppendInterfaceOrReflectNext(r.Value(), kv)
|
||||
f.Buffer.B = append(f.Buffer.B, ' ')
|
||||
}
|
||||
|
||||
// Drop last space
|
||||
if n > 0 {
|
||||
f.Buffer.Truncate(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) AppendStruct(v reflect.Value, t reflect.Type) {
|
||||
// Get value type
|
||||
f.VType = t.String()
|
||||
|
||||
// Append field formatted struct fields
|
||||
f._AppendFieldType(func(f format) {
|
||||
f.AppendStructFields(v, t)
|
||||
})
|
||||
}
|
||||
|
||||
func (f format) AppendStructFields(v reflect.Value, t reflect.Type) {
|
||||
// Get field no.
|
||||
n := v.NumField()
|
||||
|
||||
// Iterate struct fields
|
||||
for i := 0; i < n; i++ {
|
||||
vfield := v.Field(i)
|
||||
tfield := t.Field(i)
|
||||
|
||||
// Append field name
|
||||
f.AppendStringKey(tfield.Name)
|
||||
f.Buffer.B = append(f.Buffer.B, '=')
|
||||
f.SetValue().AppendInterfaceOrReflectNext(vfield, tfield.Type)
|
||||
|
||||
// Append separator
|
||||
f.Buffer.B = append(f.Buffer.B, ' ')
|
||||
}
|
||||
|
||||
// Drop last space
|
||||
if n > 0 {
|
||||
f.Buffer.Truncate(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) _AppendMethodType(method func() string, i interface{}) (ok bool) {
|
||||
// Verbose -- no methods
|
||||
if f.Verbose() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Catch nil type
|
||||
if isNil(i) {
|
||||
f.AppendNil()
|
||||
return true
|
||||
}
|
||||
|
||||
// Catch any panics
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
// DON'T recurse catchPanic()
|
||||
if f.Panic() {
|
||||
panic(r)
|
||||
}
|
||||
|
||||
// Attempt to decode panic into buf
|
||||
f.Buffer.B = append(f.Buffer.B, `!{PANIC=`...)
|
||||
f.SetPanic().AppendInterfaceOrReflect(r)
|
||||
f.Buffer.B = append(f.Buffer.B, '}')
|
||||
|
||||
// Ensure no further attempts
|
||||
// to format after return
|
||||
ok = true
|
||||
}
|
||||
}()
|
||||
|
||||
// Get method result
|
||||
result := method()
|
||||
|
||||
switch {
|
||||
// Append as key formatted
|
||||
case f.Key():
|
||||
f.AppendStringKey(result)
|
||||
|
||||
// Append as always quoted
|
||||
case f.Value():
|
||||
f.AppendStringQuoted(result)
|
||||
|
||||
// Append as-is
|
||||
default:
|
||||
f.Buffer.B = append(f.Buffer.B, result...)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// _AppendPrimitiveType is a helper to append prefix/suffix for primitives (numbers/bools/bytes/runes).
|
||||
func (f format) _AppendPrimitiveType(appendPrimitive func(format)) {
|
||||
if f.Verbose() {
|
||||
// Append value with type information
|
||||
f._AppendPrimitiveTyped(appendPrimitive)
|
||||
} else {
|
||||
// Append simply as-is
|
||||
appendPrimitive(f)
|
||||
}
|
||||
}
|
||||
|
||||
// _AppendPrimitiveTyped is a helper to append prefix/suffix for primitives (numbers/bools/bytes/runes) with their types (if deref'd).
|
||||
func (f format) _AppendPrimitiveTyped(appendPrimitive func(format)) {
|
||||
if f.Derefs > 0 {
|
||||
// Is deref'd, append type info
|
||||
f.Buffer.B = append(f.Buffer.B, '(')
|
||||
f.AppendType()
|
||||
f.Buffer.WriteString(`)(`)
|
||||
appendPrimitive(f)
|
||||
f.Buffer.B = append(f.Buffer.B, ')')
|
||||
} else {
|
||||
// Simply append value
|
||||
appendPrimitive(f)
|
||||
}
|
||||
}
|
||||
|
||||
// _AppendPtrType is a helper to append prefix/suffix for ptr types (with type if necessary).
|
||||
func (f format) _AppendPtrType(appendPtr func(format)) {
|
||||
if f.Verbose() {
|
||||
// Append value with type information
|
||||
f.Buffer.B = append(f.Buffer.B, '(')
|
||||
f.AppendType()
|
||||
f.Buffer.WriteString(`)(`)
|
||||
appendPtr(f)
|
||||
f.Buffer.B = append(f.Buffer.B, ')')
|
||||
} else {
|
||||
// Append simply as-is
|
||||
appendPtr(f)
|
||||
}
|
||||
}
|
||||
|
||||
// _AppendArray is a helper to append prefix/suffix for array-types.
|
||||
func (f format) _AppendArray(appendArray func(format)) {
|
||||
f.Buffer.B = append(f.Buffer.B, '[')
|
||||
appendArray(f)
|
||||
f.Buffer.B = append(f.Buffer.B, ']')
|
||||
}
|
||||
|
||||
// _AppendArrayTyped is a helper to append prefix/suffix for array-types with their types.
|
||||
func (f format) _AppendArrayTyped(appendArray func(format)) {
|
||||
f.AppendType()
|
||||
f.Buffer.B = append(f.Buffer.B, '{')
|
||||
appendArray(f)
|
||||
f.Buffer.B = append(f.Buffer.B, '}')
|
||||
}
|
||||
|
||||
// _AppendFields is a helper to append prefix/suffix for field-types (with type if necessary).
|
||||
func (f format) _AppendFieldType(appendFields func(format)) {
|
||||
if f.Verbose() {
|
||||
f.AppendType()
|
||||
}
|
||||
f.Buffer.B = append(f.Buffer.B, '{')
|
||||
appendFields(f)
|
||||
f.Buffer.B = append(f.Buffer.B, '}')
|
||||
}
|
||||
|
||||
// byte2str returns 'c' as a string, escaping if necessary.
|
||||
func byte2str(c byte) string {
|
||||
switch c {
|
||||
case '\a':
|
||||
return `\a`
|
||||
case '\b':
|
||||
return `\b`
|
||||
case '\f':
|
||||
return `\f`
|
||||
case '\n':
|
||||
return `\n`
|
||||
case '\r':
|
||||
return `\r`
|
||||
case '\t':
|
||||
return `\t`
|
||||
case '\v':
|
||||
return `\v`
|
||||
case '\'':
|
||||
return `\\`
|
||||
default:
|
||||
if c < ' ' {
|
||||
const hex = "0123456789abcdef"
|
||||
return `\x` +
|
||||
string(hex[c>>4]) +
|
||||
string(hex[c&0xF])
|
||||
}
|
||||
return string(c)
|
||||
}
|
||||
}
|
||||
349
vendor/codeberg.org/gruf/go-kv/format/formatter.go
generated
vendored
Normal file
349
vendor/codeberg.org/gruf/go-kv/format/formatter.go
generated
vendored
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
package format
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"codeberg.org/gruf/go-byteutil"
|
||||
)
|
||||
|
||||
// Formatter allows configuring value and string formatting.
|
||||
type Formatter struct {
|
||||
// MaxDepth specifies the max depth of fields the formatter will iterate.
|
||||
// Once max depth is reached, value will simply be formatted as "...".
|
||||
// e.g.
|
||||
//
|
||||
// MaxDepth=1
|
||||
// type A struct{
|
||||
// Nested B
|
||||
// }
|
||||
// type B struct{
|
||||
// Nested C
|
||||
// }
|
||||
// type C struct{
|
||||
// Field string
|
||||
// }
|
||||
//
|
||||
// Append(&buf, A{}) => {Nested={Nested={Field=...}}}
|
||||
MaxDepth uint8
|
||||
}
|
||||
|
||||
// Append will append formatted form of supplied values into 'buf'.
|
||||
func (f *Formatter) Append(buf *byteutil.Buffer, v ...interface{}) {
|
||||
fmt := format{Buffer: buf, Config: f}
|
||||
for i := 0; i < len(v); i++ {
|
||||
fmt.AppendInterfaceOrReflect(v[i])
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, ' ')
|
||||
}
|
||||
if len(v) > 0 {
|
||||
fmt.Buffer.Truncate(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Appendf will append the formatted string with supplied values into 'buf'.
|
||||
// Supported format directives:
|
||||
// - '{}' => format supplied arg, in place
|
||||
// - '{0}' => format arg at index 0 of supplied, in place
|
||||
// - '{:?}' => format supplied arg verbosely, in place
|
||||
// - '{:k}' => format supplied arg as key, in place
|
||||
// - '{:v}' => format supplied arg as value, in place
|
||||
//
|
||||
// To escape either of '{}' simply append an additional brace e.g.
|
||||
// - '{{' => '{'
|
||||
// - '}}' => '}'
|
||||
// - '{{}}' => '{}'
|
||||
// - '{{:?}}' => '{:?}'
|
||||
//
|
||||
// More formatting directives might be included in the future.
|
||||
func (f *Formatter) Appendf(buf *byteutil.Buffer, s string, a ...interface{}) {
|
||||
const (
|
||||
// ground state
|
||||
modeNone = uint8(0)
|
||||
|
||||
// prev reached '{'
|
||||
modeOpen = uint8(1)
|
||||
|
||||
// prev reached '}'
|
||||
modeClose = uint8(2)
|
||||
|
||||
// parsing directive index
|
||||
modeIdx = uint8(3)
|
||||
|
||||
// parsing directive operands
|
||||
modeOp = uint8(4)
|
||||
)
|
||||
|
||||
var (
|
||||
// mode is current parsing mode
|
||||
mode uint8
|
||||
|
||||
// arg is the current arg index
|
||||
arg int
|
||||
|
||||
// carg is current directive-set arg index
|
||||
carg int
|
||||
|
||||
// last is the trailing cursor to see slice windows
|
||||
last int
|
||||
|
||||
// idx is the current index in 's'
|
||||
idx int
|
||||
|
||||
// fmt is the base argument formatter
|
||||
fmt = format{
|
||||
Config: f,
|
||||
Buffer: buf,
|
||||
}
|
||||
|
||||
// NOTE: these functions are defined here as function
|
||||
// locals as it turned out to be better for performance
|
||||
// doing it this way, than encapsulating their logic in
|
||||
// some kind of parsing structure. Maybe if the parser
|
||||
// was pooled along with the buffers it might work out
|
||||
// better, but then it makes more internal functions i.e.
|
||||
// .Append() .Appendf() less accessible outside package.
|
||||
//
|
||||
// Currently, passing '-gcflags "-l=4"' causes a not
|
||||
// insignificant decrease in ns/op, which is likely due
|
||||
// to more aggressive function inlining, which this
|
||||
// function can obviously stand to benefit from :)
|
||||
|
||||
// Str returns current string window slice, and updates
|
||||
// the trailing cursor 'last' to current 'idx'
|
||||
Str = func() string {
|
||||
str := s[last:idx]
|
||||
last = idx
|
||||
return str
|
||||
}
|
||||
|
||||
// MoveUp moves the trailing cursor 'last' just past 'idx'
|
||||
MoveUp = func() {
|
||||
last = idx + 1
|
||||
}
|
||||
|
||||
// MoveUpTo moves the trailing cursor 'last' either up to
|
||||
// closest '}', or current 'idx', whichever is furthest.
|
||||
// NOTE: by calling bytealg.IndexByteString() directly (and
|
||||
// not the strconv pass-through, we shave-off complexity
|
||||
// which allows this function to be inlined).
|
||||
MoveUpTo = func() {
|
||||
i := strings.IndexByte(s[idx:], '}')
|
||||
if i >= 0 {
|
||||
idx += i
|
||||
}
|
||||
MoveUp()
|
||||
}
|
||||
|
||||
// ParseIndex parses an integer from the current string
|
||||
// window, updating 'last' to 'idx'. The string window
|
||||
// is ASSUMED to contain only valid ASCII numbers. This
|
||||
// only returns false if number exceeds platform int size
|
||||
ParseIndex = func() bool {
|
||||
var str string
|
||||
|
||||
// Get current window
|
||||
if str = Str(); len(str) < 1 {
|
||||
return true
|
||||
}
|
||||
|
||||
// Index HAS to fit within platform integer size
|
||||
if !(strconv.IntSize == 32 && (0 < len(s) && len(s) < 10)) ||
|
||||
!(strconv.IntSize == 64 && (0 < len(s) && len(s) < 19)) {
|
||||
return false
|
||||
}
|
||||
|
||||
carg = 0
|
||||
|
||||
// Build integer from string
|
||||
for i := 0; i < len(str); i++ {
|
||||
carg = carg*10 + int(str[i]-'0')
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// ValidOp checks that for current ending idx, that a valid
|
||||
// operand was achieved -- only 0, 1 are valid numbers.
|
||||
ValidOp = func() bool {
|
||||
diff := (idx - last)
|
||||
last = idx
|
||||
return diff < 2
|
||||
}
|
||||
|
||||
// AppendArg will take either the directive-set, or
|
||||
// iterated arg index, check within bounds of 'a' and
|
||||
// append the that argument formatted to the buffer.
|
||||
// On failure, it will append an error string
|
||||
AppendArg = func() {
|
||||
// Look for idx
|
||||
if carg < 0 {
|
||||
carg = arg
|
||||
}
|
||||
|
||||
// Incr idx
|
||||
arg++
|
||||
|
||||
if carg < len(a) {
|
||||
// Append formatted argument value
|
||||
fmt.AppendInterfaceOrReflect(a[carg])
|
||||
} else {
|
||||
// No argument found for index
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, `!{MISSING_ARG}`...)
|
||||
}
|
||||
}
|
||||
|
||||
// Reset will reset the mode to ground, the flags
|
||||
// to empty and parsed 'carg' to empty
|
||||
Reset = func() {
|
||||
mode = modeNone
|
||||
fmt.CurDepth = 0
|
||||
fmt.Flags = 0
|
||||
fmt.VType = ""
|
||||
fmt.Derefs = 0
|
||||
carg = -1
|
||||
}
|
||||
)
|
||||
|
||||
for idx = 0; idx < len(s); idx++ {
|
||||
// Get next char
|
||||
c := s[idx]
|
||||
|
||||
switch mode {
|
||||
// Ground mode
|
||||
case modeNone:
|
||||
switch c {
|
||||
case '{':
|
||||
// Enter open mode
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, Str()...)
|
||||
mode = modeOpen
|
||||
MoveUp()
|
||||
case '}':
|
||||
// Enter close mode
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, Str()...)
|
||||
mode = modeClose
|
||||
MoveUp()
|
||||
}
|
||||
|
||||
// Encountered open '{'
|
||||
case modeOpen:
|
||||
switch c {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
// Starting index
|
||||
mode = modeIdx
|
||||
MoveUp()
|
||||
case '{':
|
||||
// Escaped bracket
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, '{')
|
||||
mode = modeNone
|
||||
MoveUp()
|
||||
case '}':
|
||||
// Format arg
|
||||
AppendArg()
|
||||
Reset()
|
||||
MoveUp()
|
||||
case ':':
|
||||
// Starting operands
|
||||
mode = modeOp
|
||||
MoveUp()
|
||||
default:
|
||||
// Bad char, missing a close
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, `!{MISSING_CLOSE}`...)
|
||||
mode = modeNone
|
||||
MoveUpTo()
|
||||
}
|
||||
|
||||
// Encountered close '}'
|
||||
case modeClose:
|
||||
switch c {
|
||||
case '}':
|
||||
// Escaped close bracket
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, '}')
|
||||
mode = modeNone
|
||||
MoveUp()
|
||||
default:
|
||||
// Missing an open bracket
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, `!{MISSING_OPEN}`...)
|
||||
mode = modeNone
|
||||
MoveUp()
|
||||
}
|
||||
|
||||
// Preparing index
|
||||
case modeIdx:
|
||||
switch c {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
case ':':
|
||||
if !ParseIndex() {
|
||||
// Unable to parse an integer
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, `!{BAD_INDEX}`...)
|
||||
mode = modeNone
|
||||
MoveUpTo()
|
||||
} else {
|
||||
// Starting operands
|
||||
mode = modeOp
|
||||
MoveUp()
|
||||
}
|
||||
case '}':
|
||||
if !ParseIndex() {
|
||||
// Unable to parse an integer
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, `!{BAD_INDEX}`...)
|
||||
} else {
|
||||
// Format arg
|
||||
AppendArg()
|
||||
}
|
||||
Reset()
|
||||
MoveUp()
|
||||
default:
|
||||
// Not a valid index character
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, `!{BAD_INDEX}`...)
|
||||
mode = modeNone
|
||||
MoveUpTo()
|
||||
}
|
||||
|
||||
// Preparing operands
|
||||
case modeOp:
|
||||
switch c {
|
||||
case 'k':
|
||||
fmt.Flags |= IsKeyBit
|
||||
case 'v':
|
||||
fmt.Flags |= IsValBit
|
||||
case '?':
|
||||
fmt.Flags |= VboseBit
|
||||
case '}':
|
||||
if !ValidOp() {
|
||||
// Bad operands parsed
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, `!{BAD_OPERAND}`...)
|
||||
} else {
|
||||
// Format arg
|
||||
AppendArg()
|
||||
}
|
||||
Reset()
|
||||
MoveUp()
|
||||
default:
|
||||
// Not a valid operand char
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, `!{BAD_OPERAND}`...)
|
||||
Reset()
|
||||
MoveUpTo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Append any remaining
|
||||
fmt.Buffer.B = append(fmt.Buffer.B, s[last:]...)
|
||||
}
|
||||
|
||||
// formatter is the default formatter instance.
|
||||
var formatter = Formatter{
|
||||
MaxDepth: 10,
|
||||
}
|
||||
|
||||
// Append will append formatted form of supplied values into 'buf' using default formatter.
|
||||
// See Formatter.Append() for more documentation.
|
||||
func Append(buf *byteutil.Buffer, v ...interface{}) {
|
||||
formatter.Append(buf, v...)
|
||||
}
|
||||
|
||||
// Appendf will append the formatted string with supplied values into 'buf' using default formatter.
|
||||
// See Formatter.Appendf() for more documentation.
|
||||
func Appendf(buf *byteutil.Buffer, s string, a ...interface{}) {
|
||||
formatter.Appendf(buf, s, a...)
|
||||
}
|
||||
56
vendor/codeberg.org/gruf/go-kv/format/util.go
generated
vendored
Normal file
56
vendor/codeberg.org/gruf/go-kv/format/util.go
generated
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
package format
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// ContainsSpaceOrTab checks if "s" contains space or tabs.
|
||||
func ContainsSpaceOrTab(s string) bool {
|
||||
if i := strings.IndexByte(s, ' '); i != -1 {
|
||||
return true // note using indexbyte as it is ASM.
|
||||
} else if i := strings.IndexByte(s, '\t'); i != -1 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ContainsDoubleQuote checks if "s" contains a double quote.
|
||||
func ContainsDoubleQuote(s string) bool {
|
||||
return (strings.IndexByte(s, '"') != -1)
|
||||
}
|
||||
|
||||
// AppendEscape will append 's' to 'dst' and escape any double quotes.
|
||||
func AppendEscape(dst []byte, str string) []byte {
|
||||
var delim bool
|
||||
for i := range str {
|
||||
if str[i] == '\\' && !delim {
|
||||
// Set delim flag
|
||||
delim = true
|
||||
continue
|
||||
} else if str[i] == '"' && !delim {
|
||||
// Append escaped double quote
|
||||
dst = append(dst, `\"`...)
|
||||
continue
|
||||
} else if delim {
|
||||
// Append skipped slash
|
||||
dst = append(dst, `\`...)
|
||||
delim = false
|
||||
}
|
||||
|
||||
// Append char as-is
|
||||
dst = append(dst, str[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// isNil will safely check if 'v' is nil without dealing with weird Go interface nil bullshit.
|
||||
func isNil(i interface{}) bool {
|
||||
type eface struct{ _type, data unsafe.Pointer } //nolint
|
||||
return (*(*eface)(unsafe.Pointer(&i))).data == nil //nolint
|
||||
}
|
||||
|
||||
// b2s converts a byteslice to string without allocation.
|
||||
func b2s(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue