diff options
author | 2022-01-16 18:52:30 +0100 | |
---|---|---|
committer | 2022-01-16 18:52:30 +0100 | |
commit | 6f5ccf435585e43a00e3cc50f4bcefac36ada818 (patch) | |
tree | ba368d27464b79b1e5d010c0662fd3e340bf108e /vendor/codeberg.org/gruf/go-format/formatter.go | |
parent | add go-runners to readme (diff) | |
download | gotosocial-6f5ccf435585e43a00e3cc50f4bcefac36ada818.tar.xz |
update dependencies
Diffstat (limited to 'vendor/codeberg.org/gruf/go-format/formatter.go')
-rw-r--r-- | vendor/codeberg.org/gruf/go-format/formatter.go | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/vendor/codeberg.org/gruf/go-format/formatter.go b/vendor/codeberg.org/gruf/go-format/formatter.go new file mode 100644 index 000000000..640fa3f04 --- /dev/null +++ b/vendor/codeberg.org/gruf/go-format/formatter.go @@ -0,0 +1,352 @@ +package format + +import ( + "strings" +) + +// 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 *Buffer, v ...interface{}) { + for _, v := range v { + appendIfaceOrRValue(format{maxd: f.MaxDepth, buf: buf}, v) + buf.AppendByte(' ') + } + if len(v) > 0 { + buf.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 *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{ + maxd: f.MaxDepth, + buf: 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 + MoveUpTo = func() { + if i := strings.IndexByte(s[idx:], '}'); 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 { + // Get current window + str := Str() + if len(str) < 1 { + return true + } + + // Index HAS to fit within platform int + if !can32bitInt(str) && !can64bitInt(str) { + return false + } + + // Build integer from string + carg = 0 + for _, c := range []byte(str) { + carg = carg*10 + int(c-'0') + } + + return true + } + + // ParseOp parses operands from the current string + // window, updating 'last' to 'idx'. The string window + // is ASSUMED to contain only valid operand ASCII. This + // returns success on parsing of operand logic + ParseOp = func() bool { + // Get current window + str := Str() + if len(str) < 1 { + return true + } + + // (for now) only + // accept length = 1 + if len(str) > 1 { + return false + } + + switch str[0] { + case 'k': + fmt.flags |= isKeyBit + case 'v': + fmt.flags |= isValBit + case '?': + fmt.flags |= vboseBit + } + + return true + } + + // 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 + appendIfaceOrRValue(fmt, a[carg]) + } else { + // No argument found for index + buf.AppendString(`!{MISSING_ARG}`) + } + } + + // Reset will reset the mode to ground, the flags + // to empty and parsed 'carg' to empty + Reset = func() { + mode = modeNone + fmt.flags = 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 + buf.AppendString(Str()) + mode = modeOpen + MoveUp() + case '}': + // Enter close mode + buf.AppendString(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 + buf.AppendByte('{') + mode = modeNone + MoveUp() + case '}': + // Format arg + AppendArg() + Reset() + MoveUp() + case ':': + // Starting operands + mode = modeOp + MoveUp() + default: + // Bad char, missing a close + buf.AppendString(`!{MISSING_CLOSE}`) + mode = modeNone + MoveUpTo() + } + + // Encountered close '}' + case modeClose: + switch c { + case '}': + // Escaped close bracket + buf.AppendByte('}') + mode = modeNone + MoveUp() + default: + // Missing an open bracket + buf.AppendString(`!{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 + buf.AppendString(`!{BAD_INDEX}`) + mode = modeNone + MoveUpTo() + } else { + // Starting operands + mode = modeOp + MoveUp() + } + case '}': + if !ParseIndex() { + // Unable to parse an integer + buf.AppendString(`!{BAD_INDEX}`) + } else { + // Format arg + AppendArg() + } + Reset() + MoveUp() + default: + // Not a valid index character + buf.AppendString(`!{BAD_INDEX}`) + mode = modeNone + MoveUpTo() + } + + // Preparing operands + case modeOp: + switch c { + case 'k', 'v', '?': + // TODO: set flags as received + case '}': + if !ParseOp() { + // Unable to parse operands + buf.AppendString(`!{BAD_OPERAND}`) + } else { + // Format arg + AppendArg() + } + Reset() + MoveUp() + default: + // Not a valid operand char + buf.AppendString(`!{BAD_OPERAND}`) + Reset() + MoveUpTo() + } + } + } + + // Append any remaining + buf.AppendString(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 *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 *Buffer, s string, a ...interface{}) { + formatter.Appendf(buf, s, a...) +} |