package fast
import (
"math"
"strconv"
)
// This file hosts integer and float encoding helpers that complement the
// pooled Buffer type. They exist so that the hot path in the JSON encoder
// can avoid importing strconv directly (allowing the rest of the tree to be
// compiled without it during TinyGo experiments).
// Base-10 lookup for two-digit integers. Useful for formatting timestamps
// without allocating through strconv.Itoa in the common case of small
// values such as minutes, seconds, and milliseconds.
var twoDigits = [100][2]byte{}
func init() {
for i := 0; i < 100; i++ {
twoDigits[i][0] = byte('0' + i/10)
twoDigits[i][1] = byte('0' + i%10)
}
}
// AppendTwoDigits writes v zero-padded to exactly two bytes. It panics if v
// is outside [0,99], which is fine for the intended callers (Hour/Minute/
// Second accessors from the time package).
func AppendTwoDigits(b *Buffer, v int) {
if v < 0 || v > 99 {
panic("fast.AppendTwoDigits: out of range")
}
pair := twoDigits[v]
b.b = append(b.b, pair[0], pair[1])
}
// AppendQuotedString appends s surrounded by double quotes. It is the
// minimal fast path: for strings that need escaping, the escape package is
// used instead.
func AppendQuotedString(b *Buffer, s string) {
b.b = append(b.b, '"')
b.b = append(b.b, s...)
b.b = append(b.b, '"')
}
// AppendFloatSafe is AppendFloat with NaN and +/-Inf collapsed to null
// literal tokens so the result is always valid JSON.
func AppendFloatSafe(b *Buffer, f float64) {
switch {
case math.IsNaN(f):
b.AppendString("null")
case math.IsInf(f, 1):
b.AppendString("null")
case math.IsInf(f, -1):
b.AppendString("null")
default:
b.b = strconv.AppendFloat(b.b, f, 'g', -1, 64)
}
}
// AppendBool writes the literal true or false tokens.
func AppendBool(b *Buffer, v bool) {
if v {
b.AppendString("true")
} else {
b.AppendString("false")
}
}
// AppendHex writes v as a fixed-width lowercase hex string of width bytes.
func AppendHex(b *Buffer, v uint64, width int) {
const digits = "0123456789abcdef"
var tmp [16]byte
for i := width - 1; i >= 0; i-- {
tmp[i] = digits[v&0xf]
v >>= 4
}
b.b = append(b.b, tmp[:width]...)
}
// AppendMillis writes d in milliseconds (integer).
func AppendMillis(b *Buffer, ms int64) {
AppendInt(b, ms)
}
// AppendKeyValueSep writes the characters separating a key from a value in
// an object. Centralised here so alternative encodings (e.g. logfmt) can
// swap it out.
func AppendKeyValueSep(b *Buffer) { b.AppendByte(':') }
// AppendPairSep writes the character separating two key-value pairs.
func AppendPairSep(b *Buffer) { b.AppendByte(',') }