diff options
author | 2022-07-19 09:47:55 +0100 | |
---|---|---|
committer | 2022-07-19 10:47:55 +0200 | |
commit | 098dbe6ff4f59652181c8e0e3873fbfcf0e65ea3 (patch) | |
tree | 17036ad9db68c3080e1e91279c8bce9f9ea6e5c3 /vendor/codeberg.org/gruf/go-kv/format/formatter.go | |
parent | [bugfix] Markdown format fixes (#718) (diff) | |
download | gotosocial-098dbe6ff4f59652181c8e0e3873fbfcf0e65ea3.tar.xz |
[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>
Diffstat (limited to 'vendor/codeberg.org/gruf/go-kv/format/formatter.go')
-rw-r--r-- | vendor/codeberg.org/gruf/go-kv/format/formatter.go | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/vendor/codeberg.org/gruf/go-kv/format/formatter.go b/vendor/codeberg.org/gruf/go-kv/format/formatter.go new file mode 100644 index 000000000..fd8cf98df --- /dev/null +++ b/vendor/codeberg.org/gruf/go-kv/format/formatter.go @@ -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...) +} |